layout: Refactor try_append_to_line to eliminate duplicate code.

This commit is contained in:
Patrick Walton 2013-12-09 18:54:17 -08:00
parent 594eb0067a
commit 7148a28611

View file

@ -277,10 +277,56 @@ impl LineboxScanner {
} }
/// Returns false only if we should break the line. /// Performs float collision avoidance. This is called when adding a box is going to increase
fn try_append_to_line(&mut self, in_box: @Box, flow: &mut InlineFlow) -> bool { /// the height, and because of that we will collide with some floats.
let line_is_empty: bool = self.pending_line.range.length() == 0; ///
/// 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 { if line_is_empty {
let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y, flow); let (line_bounds, _) = self.initial_line_placement(in_box, self.cur_y, flow);
self.pending_line.bounds.origin = line_bounds.origin; self.pending_line.bounds.origin = line_bounds.origin;
@ -294,89 +340,71 @@ impl LineboxScanner {
self.pending_line.green_zone, self.pending_line.green_zone,
in_box.debug_str()); in_box.debug_str());
let green_zone = self.pending_line.green_zone; let green_zone = self.pending_line.green_zone;
//assert!(green_zone.width >= self.pending_line.bounds.size.width && // NB: At this point, if `green_zone.width < self.pending_line.bounds.size.width` or
// green_zone.height >= self.pending_line.bounds.size.height, // `green_zone.height < self.pending_line.bounds.size.height`, then we committed a line
// "Committed a line that overlaps with floats"); // that overlaps with floats.
let new_height = self.new_height_for_line(in_box); let new_height = self.new_height_for_line(in_box);
if new_height > green_zone.height { if new_height > green_zone.height {
debug!("LineboxScanner: entering float collision avoider!"); // Uh-oh. Float collision imminent. Enter the float collision avoider…
return self.avoid_floats(in_box, flow, new_height, line_is_empty)
// 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;
}
} }
// If we're not going to overflow the green zone vertically, we might still do so // 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 // horizontally. We'll try to place the whole box on this line and break somewhere if it
// if it doesn't fit. // doesn't fit.
let new_width = self.pending_line.bounds.size.width + in_box.position.get().size.width; let new_width = self.pending_line.bounds.size.width + in_box.position.get().size.width;
if new_width <= green_zone.width { if new_width <= green_zone.width {
debug!("LineboxScanner: case=box fits without splitting"); debug!("LineboxScanner: case=box fits without splitting");
self.push_box_to_line(in_box); self.push_box_to_line(in_box);
return true; return true
} }
if !in_box.can_split() { 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 { if line_is_empty {
debug!("LineboxScanner: case=box can't split and line {:u} is empty, so \ debug!("LineboxScanner: case=box can't split and line {:u} is empty, so \
overflowing.", overflowing.",
self.lines.len()); self.lines.len());
self.push_box_to_line(in_box); self.push_box_to_line(in_box)
return true;
} else { } else {
debug!("LineboxScanner: Case=box can't split, not appending."); debug!("LineboxScanner: Case=box can't split, not appending.");
return false;
} }
} else { return line_is_empty
let available_width = green_zone.width - self.pending_line.bounds.size.width; }
match in_box.split_to_width(available_width, line_is_empty) { let available_width = green_zone.width - self.pending_line.bounds.size.width;
CannotSplit(_) => { 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}", error!("LineboxScanner: Tried to split unsplittable render box! {:s}",
in_box.debug_str()); in_box.debug_str());
return false; return false
} }
SplitDidFit(left, right) => { (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."); 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) { match (left, right) {
(Some(left_box), Some(right_box)) => { (Some(left_box), Some(right_box)) => {
self.push_box_to_line(left_box); self.push_box_to_line(left_box);
@ -386,40 +414,11 @@ impl LineboxScanner {
(None, Some(right_box)) => self.push_box_to_line(right_box), (None, Some(right_box)) => self.push_box_to_line(right_box),
(None, None) => error!("LineboxScanner: This split case makes no sense!"), (None, None) => error!("LineboxScanner: This split case makes no sense!"),
} }
return true;
} 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;
}
}
}
}
} }
// unconditional push // An unconditional push.
fn push_box_to_line(&mut self, box: @Box) { fn push_box_to_line(&mut self, box: @Box) {
debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len()); debug!("LineboxScanner: Pushing box {} to line {:u}", box.debug_id(), self.lines.len());