mirror of
https://github.com/servo/servo.git
synced 2025-08-11 16:35:33 +01:00
Hook up linebox scanner, and fix many glitches in the scanning algorithm.
This commit is contained in:
parent
5e7f9fc585
commit
5c5a7a1866
3 changed files with 75 additions and 44 deletions
|
@ -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); },
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue