Hook up linebox scanner, and fix many glitches in the scanning algorithm.

This commit is contained in:
Brian J. Burg 2012-10-16 21:04:35 -07:00
parent 5e7f9fc585
commit 5c5a7a1866
3 changed files with 75 additions and 44 deletions

View file

@ -94,9 +94,10 @@ pub enum RenderBox {
pub enum SplitBoxResult {
CannotSplit(@RenderBox),
SplitUnnecessary(@RenderBox),
SplitDidFit(@RenderBox, @RenderBox),
SplitDidNotFit(@RenderBox, @RenderBox)
// in general, when splitting the left or right side can
// be zero length, due to leading/trailing trimmable whitespace
SplitDidFit(Option<@RenderBox>, Option<@RenderBox>),
SplitDidNotFit(Option<@RenderBox>, Option<@RenderBox>)
}
enum InlineSpacerSide {
@ -190,51 +191,65 @@ impl RenderBox : RenderBoxMethods {
let mut left_length : uint = 0;
let mut right_offset : Option<uint> = None;
let mut right_length : Option<uint> = None;
debug!("split_to_width: splitting text box (strlen=%u, off=%u, len=%u, avail_width=%?)",
data.run.text.len(), data.offset, data.length, max_width);
do data.run.iter_indivisible_pieces_for_range(data.offset, data.length) |off, len| {
debug!("split_to_width: considering range (off=%u, len=%u, remain_width=%?)",
off, len, remaining_width);
let metrics = data.run.metrics_for_range(off, len);
let advance = metrics.advance_width;
let should_continue : bool;
if advance < remaining_width {
if starts_line && data.run.range_is_trimmable_whitespace(off, len) {
if advance <= remaining_width {
should_continue = true;
if starts_line && i == 0 && data.run.range_is_trimmable_whitespace(off, len) {
debug!("split_to_width: case=skipping leading trimmable whitespace");
left_offset += len;
} else {
debug!("split_to_width: case=enlarging span");
remaining_width -= advance;
left_length += len;
}
should_continue = true;
} else if advance > remaining_width
&& data.run.range_is_trimmable_whitespace(off, len) {
// if there are still things after the trimmable whitespace, create right chunk
if off + len < data.length {
right_offset = Some(off + len);
right_length = Some(data.length - (off + len));
}
} else { /* advance > remaining_width */
should_continue = false;
} else {
right_offset = Some(off);
right_length = Some(data.length - off);
should_continue = false;
}
if data.run.range_is_trimmable_whitespace(off, len) {
// if there are still things after the trimmable whitespace, create right chunk
if off + len < data.offset + data.length {
debug!("split_to_width: case=skipping trimmable trailing whitespace, then split remainder");
right_offset = Some(off + len);
right_length = Some((data.offset + data.length) - (off + len));
} else {
debug!("split_to_width: case=skipping trimmable trailing whitespace");
}
} else if off < data.length + data.offset {
// still things left, create right chunk
right_offset = Some(off);
right_length = Some((data.offset + data.length) - off);
debug!("split_to_width: case=splitting remainder with right span: (off=%u, len=%u)",
off, (data.offset + data.length) - off);
}
}
i += 1;
should_continue
}
assert left_length > 0;
let left_box = layout::text::adapt_textbox_with_range(self.d(), data.run,
left_offset, left_length);
let left_box = if left_length > 0 {
Some(layout::text::adapt_textbox_with_range(self.d(), data.run,
left_offset, left_length))
} else { None };
match (right_offset, right_length) {
(Some(right_off), Some(right_len)) => {
assert right_len > 0;
let right_box = layout::text::adapt_textbox_with_range(self.d(), data.run,
right_off, right_len);
if i == 1 { return SplitDidNotFit(left_box, right_box); }
else { return SplitDidFit(left_box, right_box); }
return if i == 1 || left_box.is_none() {
SplitDidNotFit(left_box, Some(right_box))
} else {
SplitDidFit(left_box, Some(right_box))
}
},
(None, None) => { return SplitUnnecessary(left_box); },
(_, _) => fail ~"Must specify right box's offset and length, not one or other."
(_, _) => { return SplitDidFit(left_box, None); },
}
},
}

View file

@ -307,13 +307,13 @@ impl LineboxScanner {
loop {
// acquire the next box to lay out from work list or box list
let cur_box = match (self.work_list.pop(), boxes.len()) {
(Some(box), _) => {
let cur_box = match self.work_list.pop() {
Some(box) => {
debug!("LineboxScanner: Working with box from work list: b%d", box.d().id);
box
},
(None, 0) => { break },
(None, _) => {
None => {
if i == boxes.len() { break; }
let box = boxes[i]; i += 1;
debug!("LineboxScanner: Working with box from box list: b%d", box.d().id);
box
@ -325,6 +325,8 @@ impl LineboxScanner {
debug!("LineboxScanner: Box wasn't appended, because line %u was full.",
self.line_spans.len());
self.flush_current_line();
} else {
debug!("LineboxScanner: appended a box to line %u", self.line_spans.len());
}
}
@ -352,7 +354,6 @@ impl LineboxScanner {
debug!("LineboxScanner: Flushing line %u: %?",
self.line_spans.len(), self.pending_line);
// set box horizontal offsets
let boxes = &self.flow.inline().boxes;
let line_span = copy self.pending_line.span;
let mut offset_x = au(0);
// TODO: interpretation of CSS 'text-direction' and 'text-align'
@ -360,7 +361,7 @@ impl LineboxScanner {
debug!("LineboxScanner: Setting horizontal offsets for boxes in line %u range: %?",
self.line_spans.len(), line_span);
for uint::range(line_span.start as uint, (line_span.start + line_span.len) as uint) |i| {
let box_data = &boxes[i].d();
let box_data = &self.new_boxes[i].d();
box_data.position.origin.x = offset_x;
offset_x += box_data.position.size.width;
}
@ -406,15 +407,17 @@ impl LineboxScanner {
error!("LineboxScanner: Tried to split unsplittable render box! %s", in_box.debug_str());
return false;
},
SplitUnnecessary(_) => {
error!("LineboxScanner: Tried to split when un-split piece was small enough! %s", in_box.debug_str());
self.push_box_to_line(in_box);
return true;
},
SplitDidFit(left, right) => {
debug!("LineboxScanner: case=split box did fit; deferring remainder box.");
self.push_box_to_line(left);
self.work_list.push_head(right);
match (left, right) {
(Some(left_box), Some(right_box)) => {
self.push_box_to_line(left_box);
self.work_list.push_head(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) => { fail ~"This split case makes no sense!" }
}
return true;
},
SplitDidNotFit(left, right) => {
@ -422,8 +425,19 @@ impl LineboxScanner {
debug!("LineboxScanner: case=split box didn't fit and line %u is empty, so overflowing and deferring remainder box.",
self.line_spans.len());
// TODO: signal that horizontal overflow happened?
self.push_box_to_line(left);
self.work_list.push_head(right);
match (left, right) {
(Some(left_box), Some(right_box)) => {
self.push_box_to_line(left_box);
self.work_list.push_head(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) => { fail ~"This split case makes no sense!" }
}
return true;
} else {
debug!("LineboxScanner: case=split box didn't fit, not appending and deferring original box.");
@ -503,7 +517,7 @@ impl FlowContext : InlineLayout {
/* Recursively (top-down) determines the actual width of child
contexts and boxes. When called on this context, the context has
had its width set by the parent context. */
fn assign_widths_inline(@self, _ctx: &LayoutContext) {
fn assign_widths_inline(@self, ctx: &LayoutContext) {
assert self.starts_inline_flow();
// initialize (content) box widths, if they haven't been
@ -520,8 +534,8 @@ impl FlowContext : InlineLayout {
};
} // for boxes.each |box|
//let scanner = LineBoxScanner(self);
//scanner.scan_for_lines(ctx);
let scanner = LineboxScanner(self);
scanner.scan_for_lines(ctx);
/* There are no child contexts, so stop here. */

View file

@ -24,6 +24,8 @@ pub fn TextBoxData(run: @TextRun, offset: uint, length: uint) -> TextBoxData {
pub fn adapt_textbox_with_range(box_data: &RenderBoxData, run: @TextRun,
offset: uint, length: uint) -> @RenderBox {
debug!("Creating textbox with span: (strlen=%u, off=%u, len=%u) of textrun: %s",
run.text.len(), offset, length, run.text);
let new_box_data = copy *box_data;
let new_text_data = TextBoxData(run, offset, length);
let metrics = run.metrics_for_range(offset, length);