mirror of
https://github.com/servo/servo.git
synced 2025-08-12 08:55:32 +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 {
|
pub enum SplitBoxResult {
|
||||||
CannotSplit(@RenderBox),
|
CannotSplit(@RenderBox),
|
||||||
SplitUnnecessary(@RenderBox),
|
// in general, when splitting the left or right side can
|
||||||
SplitDidFit(@RenderBox, @RenderBox),
|
// be zero length, due to leading/trailing trimmable whitespace
|
||||||
SplitDidNotFit(@RenderBox, @RenderBox)
|
SplitDidFit(Option<@RenderBox>, Option<@RenderBox>),
|
||||||
|
SplitDidNotFit(Option<@RenderBox>, Option<@RenderBox>)
|
||||||
}
|
}
|
||||||
|
|
||||||
enum InlineSpacerSide {
|
enum InlineSpacerSide {
|
||||||
|
@ -190,51 +191,65 @@ impl RenderBox : RenderBoxMethods {
|
||||||
let mut left_length : uint = 0;
|
let mut left_length : uint = 0;
|
||||||
let mut right_offset : Option<uint> = None;
|
let mut right_offset : Option<uint> = None;
|
||||||
let mut right_length : 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| {
|
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 metrics = data.run.metrics_for_range(off, len);
|
||||||
let advance = metrics.advance_width;
|
let advance = metrics.advance_width;
|
||||||
let should_continue : bool;
|
let should_continue : bool;
|
||||||
|
|
||||||
if advance < remaining_width {
|
if advance <= remaining_width {
|
||||||
if starts_line && data.run.range_is_trimmable_whitespace(off, len) {
|
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;
|
left_offset += len;
|
||||||
} else {
|
} else {
|
||||||
|
debug!("split_to_width: case=enlarging span");
|
||||||
remaining_width -= advance;
|
remaining_width -= advance;
|
||||||
left_length += len;
|
left_length += len;
|
||||||
}
|
}
|
||||||
should_continue = true;
|
} else { /* advance > remaining_width */
|
||||||
} 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));
|
|
||||||
}
|
|
||||||
should_continue = false;
|
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;
|
i += 1;
|
||||||
should_continue
|
should_continue
|
||||||
}
|
}
|
||||||
|
|
||||||
assert left_length > 0;
|
let left_box = if left_length > 0 {
|
||||||
let left_box = layout::text::adapt_textbox_with_range(self.d(), data.run,
|
Some(layout::text::adapt_textbox_with_range(self.d(), data.run,
|
||||||
left_offset, left_length);
|
left_offset, left_length))
|
||||||
|
} else { None };
|
||||||
|
|
||||||
match (right_offset, right_length) {
|
match (right_offset, right_length) {
|
||||||
(Some(right_off), Some(right_len)) => {
|
(Some(right_off), Some(right_len)) => {
|
||||||
assert right_len > 0;
|
|
||||||
let right_box = layout::text::adapt_textbox_with_range(self.d(), data.run,
|
let right_box = layout::text::adapt_textbox_with_range(self.d(), data.run,
|
||||||
right_off, right_len);
|
right_off, right_len);
|
||||||
if i == 1 { return SplitDidNotFit(left_box, right_box); }
|
return if i == 1 || left_box.is_none() {
|
||||||
else { return SplitDidFit(left_box, right_box); }
|
SplitDidNotFit(left_box, Some(right_box))
|
||||||
|
} else {
|
||||||
|
SplitDidFit(left_box, Some(right_box))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
(None, None) => { return SplitUnnecessary(left_box); },
|
(_, _) => { return SplitDidFit(left_box, None); },
|
||||||
(_, _) => fail ~"Must specify right box's offset and length, not one or other."
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -307,13 +307,13 @@ impl LineboxScanner {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
// acquire the next box to lay out from work list or box list
|
// acquire the next box to lay out from work list or box list
|
||||||
let cur_box = match (self.work_list.pop(), boxes.len()) {
|
let cur_box = match self.work_list.pop() {
|
||||||
(Some(box), _) => {
|
Some(box) => {
|
||||||
debug!("LineboxScanner: Working with box from work list: b%d", box.d().id);
|
debug!("LineboxScanner: Working with box from work list: b%d", box.d().id);
|
||||||
box
|
box
|
||||||
},
|
},
|
||||||
(None, 0) => { break },
|
None => {
|
||||||
(None, _) => {
|
if i == boxes.len() { break; }
|
||||||
let box = boxes[i]; i += 1;
|
let box = boxes[i]; i += 1;
|
||||||
debug!("LineboxScanner: Working with box from box list: b%d", box.d().id);
|
debug!("LineboxScanner: Working with box from box list: b%d", box.d().id);
|
||||||
box
|
box
|
||||||
|
@ -325,6 +325,8 @@ impl LineboxScanner {
|
||||||
debug!("LineboxScanner: Box wasn't appended, because line %u was full.",
|
debug!("LineboxScanner: Box wasn't appended, because line %u was full.",
|
||||||
self.line_spans.len());
|
self.line_spans.len());
|
||||||
self.flush_current_line();
|
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: %?",
|
debug!("LineboxScanner: Flushing line %u: %?",
|
||||||
self.line_spans.len(), self.pending_line);
|
self.line_spans.len(), self.pending_line);
|
||||||
// set box horizontal offsets
|
// set box horizontal offsets
|
||||||
let boxes = &self.flow.inline().boxes;
|
|
||||||
let line_span = copy self.pending_line.span;
|
let line_span = copy self.pending_line.span;
|
||||||
let mut offset_x = au(0);
|
let mut offset_x = au(0);
|
||||||
// TODO: interpretation of CSS 'text-direction' and 'text-align'
|
// 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: %?",
|
debug!("LineboxScanner: Setting horizontal offsets for boxes in line %u range: %?",
|
||||||
self.line_spans.len(), line_span);
|
self.line_spans.len(), line_span);
|
||||||
for uint::range(line_span.start as uint, (line_span.start + line_span.len) as uint) |i| {
|
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;
|
box_data.position.origin.x = offset_x;
|
||||||
offset_x += box_data.position.size.width;
|
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());
|
error!("LineboxScanner: Tried to split unsplittable render box! %s", in_box.debug_str());
|
||||||
return false;
|
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) => {
|
SplitDidFit(left, right) => {
|
||||||
debug!("LineboxScanner: case=split box did fit; deferring remainder box.");
|
debug!("LineboxScanner: case=split box did fit; deferring remainder box.");
|
||||||
self.push_box_to_line(left);
|
match (left, right) {
|
||||||
self.work_list.push_head(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;
|
return true;
|
||||||
},
|
},
|
||||||
SplitDidNotFit(left, right) => {
|
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.",
|
debug!("LineboxScanner: case=split box didn't fit and line %u is empty, so overflowing and deferring remainder box.",
|
||||||
self.line_spans.len());
|
self.line_spans.len());
|
||||||
// TODO: signal that horizontal overflow happened?
|
// TODO: signal that horizontal overflow happened?
|
||||||
self.push_box_to_line(left);
|
match (left, right) {
|
||||||
self.work_list.push_head(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;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
debug!("LineboxScanner: case=split box didn't fit, not appending and deferring original box.");
|
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
|
/* Recursively (top-down) determines the actual width of child
|
||||||
contexts and boxes. When called on this context, the context has
|
contexts and boxes. When called on this context, the context has
|
||||||
had its width set by the parent context. */
|
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();
|
assert self.starts_inline_flow();
|
||||||
|
|
||||||
// initialize (content) box widths, if they haven't been
|
// initialize (content) box widths, if they haven't been
|
||||||
|
@ -520,8 +534,8 @@ impl FlowContext : InlineLayout {
|
||||||
};
|
};
|
||||||
} // for boxes.each |box|
|
} // for boxes.each |box|
|
||||||
|
|
||||||
//let scanner = LineBoxScanner(self);
|
let scanner = LineboxScanner(self);
|
||||||
//scanner.scan_for_lines(ctx);
|
scanner.scan_for_lines(ctx);
|
||||||
|
|
||||||
/* There are no child contexts, so stop here. */
|
/* 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,
|
pub fn adapt_textbox_with_range(box_data: &RenderBoxData, run: @TextRun,
|
||||||
offset: uint, length: uint) -> @RenderBox {
|
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_box_data = copy *box_data;
|
||||||
let new_text_data = TextBoxData(run, offset, length);
|
let new_text_data = TextBoxData(run, offset, length);
|
||||||
let metrics = run.metrics_for_range(offset, length);
|
let metrics = run.metrics_for_range(offset, length);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue