mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
layout: Refactor try_append_to_line
to eliminate duplicate code.
This commit is contained in:
parent
594eb0067a
commit
7148a28611
1 changed files with 102 additions and 103 deletions
|
@ -277,10 +277,56 @@ impl LineboxScanner {
|
|||
|
||||
}
|
||||
|
||||
/// Returns false only if we should break the line.
|
||||
fn try_append_to_line(&mut self, in_box: @Box, flow: &mut InlineFlow) -> bool {
|
||||
let line_is_empty: bool = self.pending_line.range.length() == 0;
|
||||
/// Performs float collision avoidance. This is called when adding a box is going to increase
|
||||
/// the height, and because of that we will collide with some floats.
|
||||
///
|
||||
/// We have two options here:
|
||||
/// 1) Move the entire line so that it doesn't collide any more.
|
||||
/// 2) Break the line and put the new box on the next line.
|
||||
///
|
||||
/// The problem with option 1 is that we might move the line and then wind up breaking anyway,
|
||||
/// which violates the standard.
|
||||
/// But option 2 is going to look weird sometimes.
|
||||
///
|
||||
/// So we'll try to move the line whenever we can, but break if we have to.
|
||||
///
|
||||
/// Returns false if and only if we should break the line.
|
||||
fn avoid_floats(&mut self,
|
||||
in_box: @Box,
|
||||
flow: &mut InlineFlow,
|
||||
new_height: Au,
|
||||
line_is_empty: bool)
|
||||
-> bool {
|
||||
debug!("LineboxScanner: entering float collision avoider!");
|
||||
|
||||
// First predict where the next line is going to be.
|
||||
let this_line_y = self.pending_line.bounds.origin.y;
|
||||
let (next_line, first_box_width) = self.initial_line_placement(in_box, this_line_y, flow);
|
||||
let next_green_zone = next_line.size;
|
||||
|
||||
let new_width = self.pending_line.bounds.size.width + first_box_width;
|
||||
|
||||
// Now, see if everything can fit at the new location.
|
||||
if next_green_zone.width >= new_width && next_green_zone.height >= new_height {
|
||||
debug!("LineboxScanner: case=adding box collides vertically with floats: moving line");
|
||||
|
||||
self.pending_line.bounds.origin = next_line.origin;
|
||||
self.pending_line.green_zone = next_green_zone;
|
||||
|
||||
assert!(!line_is_empty, "Non-terminating line breaking");
|
||||
self.work_list.push_front(in_box);
|
||||
return true
|
||||
}
|
||||
|
||||
debug!("LineboxScanner: case=adding box collides vertically with floats: breaking line");
|
||||
self.work_list.push_front(in_box);
|
||||
false
|
||||
}
|
||||
|
||||
/// Tries to append the given box to the line, splitting it if necessary. Returns false only if
|
||||
/// we should break the line.
|
||||
fn try_append_to_line(&mut self, in_box: @Box, flow: &mut InlineFlow) -> bool {
|
||||
let line_is_empty = self.pending_line.range.length() == 0;
|
||||
if line_is_empty {
|
||||
let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y, flow);
|
||||
self.pending_line.bounds.origin = line_bounds.origin;
|
||||
|
@ -294,132 +340,85 @@ impl LineboxScanner {
|
|||
self.pending_line.green_zone,
|
||||
in_box.debug_str());
|
||||
|
||||
|
||||
let green_zone = self.pending_line.green_zone;
|
||||
|
||||
//assert!(green_zone.width >= self.pending_line.bounds.size.width &&
|
||||
// green_zone.height >= self.pending_line.bounds.size.height,
|
||||
// "Committed a line that overlaps with floats");
|
||||
// NB: At this point, if `green_zone.width < self.pending_line.bounds.size.width` or
|
||||
// `green_zone.height < self.pending_line.bounds.size.height`, then we committed a line
|
||||
// that overlaps with floats.
|
||||
|
||||
let new_height = self.new_height_for_line(in_box);
|
||||
if new_height > green_zone.height {
|
||||
debug!("LineboxScanner: entering float collision avoider!");
|
||||
|
||||
// Uh-oh. Adding this box is going to increase the height,
|
||||
// and because of that we will collide with some floats.
|
||||
|
||||
// We have two options here:
|
||||
// 1) Move the entire line so that it doesn't collide any more.
|
||||
// 2) Break the line and put the new box on the next line.
|
||||
|
||||
// The problem with option 1 is that we might move the line
|
||||
// and then wind up breaking anyway, which violates the standard.
|
||||
// But option 2 is going to look weird sometimes.
|
||||
|
||||
// So we'll try to move the line whenever we can, but break
|
||||
// if we have to.
|
||||
|
||||
// First predict where the next line is going to be
|
||||
let this_line_y = self.pending_line.bounds.origin.y;
|
||||
let (next_line, first_box_width) = self.initial_line_placement(in_box, this_line_y, flow);
|
||||
let next_green_zone = next_line.size;
|
||||
|
||||
let new_width = self.pending_line.bounds.size.width + first_box_width;
|
||||
// Now, see if everything can fit at the new location.
|
||||
if next_green_zone.width >= new_width && next_green_zone.height >= new_height{
|
||||
debug!("LineboxScanner: case=adding box collides vertically with floats: moving line");
|
||||
|
||||
self.pending_line.bounds.origin = next_line.origin;
|
||||
self.pending_line.green_zone = next_green_zone;
|
||||
|
||||
assert!(!line_is_empty, "Non-terminating line breaking");
|
||||
self.work_list.push_front(in_box);
|
||||
return true;
|
||||
} else {
|
||||
debug!("LineboxScanner: case=adding box collides vertically with floats: breaking line");
|
||||
self.work_list.push_front(in_box);
|
||||
return false;
|
||||
}
|
||||
// Uh-oh. Float collision imminent. Enter the float collision avoider…
|
||||
return self.avoid_floats(in_box, flow, new_height, line_is_empty)
|
||||
}
|
||||
|
||||
// If we're not going to overflow the green zone vertically, we might still do so
|
||||
// horizontally. We'll try to place the whole box on this line and break somewhere
|
||||
// if it doesn't fit.
|
||||
// horizontally. We'll try to place the whole box on this line and break somewhere if it
|
||||
// doesn't fit.
|
||||
|
||||
let new_width = self.pending_line.bounds.size.width + in_box.position.get().size.width;
|
||||
|
||||
if new_width <= green_zone.width {
|
||||
debug!("LineboxScanner: case=box fits without splitting");
|
||||
self.push_box_to_line(in_box);
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
|
||||
if !in_box.can_split() {
|
||||
// TODO(Issue #224): signal that horizontal overflow happened?
|
||||
// TODO(eatkinson, issue #224): Signal that horizontal overflow happened?
|
||||
if line_is_empty {
|
||||
debug!("LineboxScanner: case=box can't split and line {:u} is empty, so \
|
||||
overflowing.",
|
||||
self.lines.len());
|
||||
self.push_box_to_line(in_box);
|
||||
return true;
|
||||
self.push_box_to_line(in_box)
|
||||
} else {
|
||||
debug!("LineboxScanner: Case=box can't split, not appending.");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
let available_width = green_zone.width - self.pending_line.bounds.size.width;
|
||||
|
||||
match in_box.split_to_width(available_width, line_is_empty) {
|
||||
CannotSplit(_) => {
|
||||
error!("LineboxScanner: Tried to split unsplittable render box! {:s}",
|
||||
in_box.debug_str());
|
||||
return false;
|
||||
}
|
||||
SplitDidFit(left, right) => {
|
||||
debug!("LineboxScanner: case=split box did fit; deferring remainder box.");
|
||||
match (left, right) {
|
||||
(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),
|
||||
(None, Some(right_box)) => self.push_box_to_line(right_box),
|
||||
(None, None) => error!("LineboxScanner: This split case makes no sense!"),
|
||||
}
|
||||
return true;
|
||||
}
|
||||
SplitDidNotFit(left, right) => {
|
||||
if line_is_empty {
|
||||
debug!("LineboxScanner: case=split box didn't fit and line {:u} is empty, so overflowing and deferring remainder box.",
|
||||
self.lines.len());
|
||||
// TODO(Issue #224): signal that horizontal overflow happened?
|
||||
match (left, right) {
|
||||
(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);
|
||||
}
|
||||
(None, Some(right_box)) => {
|
||||
self.push_box_to_line(right_box);
|
||||
}
|
||||
(None, None) => {
|
||||
error!("LineboxScanner: This split case makes no sense!");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
debug!("LineboxScanner: case=split box didn't fit, not appending and deferring original box.");
|
||||
self.work_list.push_front(in_box);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return line_is_empty
|
||||
}
|
||||
|
||||
let available_width = green_zone.width - self.pending_line.bounds.size.width;
|
||||
let split = in_box.split_to_width(available_width, line_is_empty);
|
||||
let (left, right) = match (split, line_is_empty) {
|
||||
(CannotSplit(_), _) => {
|
||||
error!("LineboxScanner: Tried to split unsplittable render box! {:s}",
|
||||
in_box.debug_str());
|
||||
return false
|
||||
}
|
||||
(SplitDidNotFit(_, _), false) => {
|
||||
debug!("LineboxScanner: case=split box didn't fit, not appending and deferring \
|
||||
original box.");
|
||||
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.work_list.push_front(right_box);
|
||||
}
|
||||
(Some(left_box), None) => self.push_box_to_line(left_box),
|
||||
(None, Some(right_box)) => self.push_box_to_line(right_box),
|
||||
(None, None) => error!("LineboxScanner: This split case makes no sense!"),
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
// unconditional push
|
||||
// An unconditional push.
|
||||
fn push_box_to_line(&mut self, box: @Box) {
|
||||
debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len());
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue