mirror of
https://github.com/servo/servo.git
synced 2025-06-24 09:04:33 +01:00
More TextRange refactoring.
This commit is contained in:
parent
efca6fedfc
commit
0f050e7835
5 changed files with 44 additions and 105 deletions
|
@ -187,47 +187,47 @@ impl RenderBox : RenderBoxMethods {
|
|||
|
||||
let mut i : uint = 0;
|
||||
let mut remaining_width : au = max_width;
|
||||
let mut left_offset : uint = data.offset;
|
||||
let mut left_offset : uint = data.range.begin();
|
||||
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(TextRange(data.offset, data.length)) |subrange| {
|
||||
data.run.text.len(), data.range.begin(), data.range.length(), max_width);
|
||||
do data.run.iter_indivisible_pieces_for_range(data.range) |piece_range| {
|
||||
debug!("split_to_width: considering range (off=%u, len=%u, remain_width=%?)",
|
||||
subrange.begin(), subrange.length(), remaining_width);
|
||||
let metrics = data.run.metrics_for_range(subrange);
|
||||
piece_range.begin(), piece_range.length(), remaining_width);
|
||||
let metrics = data.run.metrics_for_range(piece_range);
|
||||
let advance = metrics.advance_width;
|
||||
let should_continue : bool;
|
||||
|
||||
if advance <= remaining_width {
|
||||
should_continue = true;
|
||||
if starts_line && i == 0 && data.run.range_is_trimmable_whitespace(subrange) {
|
||||
if starts_line && i == 0 && data.run.range_is_trimmable_whitespace(piece_range) {
|
||||
debug!("split_to_width: case=skipping leading trimmable whitespace");
|
||||
left_offset += subrange.length();
|
||||
left_offset += piece_range.length();
|
||||
} else {
|
||||
debug!("split_to_width: case=enlarging span");
|
||||
remaining_width -= advance;
|
||||
left_length += subrange.length();
|
||||
left_length += piece_range.length();
|
||||
}
|
||||
} else { /* advance > remaining_width */
|
||||
should_continue = false;
|
||||
|
||||
if data.run.range_is_trimmable_whitespace(subrange) {
|
||||
if data.run.range_is_trimmable_whitespace(piece_range) {
|
||||
// if there are still things after the trimmable whitespace, create right chunk
|
||||
if subrange.end() < data.offset + data.length {
|
||||
if piece_range.end() < data.range.end() {
|
||||
debug!("split_to_width: case=skipping trimmable trailing whitespace, then split remainder");
|
||||
right_offset = Some(subrange.end());
|
||||
right_length = Some((data.offset + data.length) - subrange.end());
|
||||
right_offset = Some(piece_range.end());
|
||||
right_length = Some(data.range.end() - piece_range.end());
|
||||
} else {
|
||||
debug!("split_to_width: case=skipping trimmable trailing whitespace");
|
||||
}
|
||||
} else if subrange.begin() < data.length + data.offset {
|
||||
} else if piece_range.begin() < data.range.end() {
|
||||
// still things left, create right chunk
|
||||
right_offset = Some(subrange.begin());
|
||||
right_length = Some((data.offset + data.length) - subrange.begin());
|
||||
right_offset = Some(piece_range.begin());
|
||||
right_length = Some(data.range.end() - piece_range.begin());
|
||||
debug!("split_to_width: case=splitting remainder with right span: (off=%u, len=%u)",
|
||||
subrange.begin(), (data.offset + data.length) - subrange.begin());
|
||||
piece_range.begin(), data.range.end() - piece_range.begin());
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
|
@ -235,14 +235,14 @@ impl RenderBox : RenderBoxMethods {
|
|||
}
|
||||
|
||||
let left_box = if left_length > 0 {
|
||||
Some(layout::text::adapt_textbox_with_range(self.d(), data.run,
|
||||
left_offset, left_length))
|
||||
Some(layout::text::adapt_textbox_with_range(self.d(), data.run,
|
||||
TextRange(left_offset, left_length)))
|
||||
} else { None };
|
||||
|
||||
match (right_offset, right_length) {
|
||||
(Some(right_off), Some(right_len)) => {
|
||||
let right_box = layout::text::adapt_textbox_with_range(self.d(), data.run,
|
||||
right_off, right_len);
|
||||
TextRange(right_off, right_len));
|
||||
return if i == 1 || left_box.is_none() {
|
||||
SplitDidNotFit(left_box, Some(right_box))
|
||||
} else {
|
||||
|
@ -270,7 +270,7 @@ impl RenderBox : RenderBoxMethods {
|
|||
// TODO: consult CSS 'width', margin, border.
|
||||
// TODO: If image isn't available, consult 'width'.
|
||||
ImageBox(_,i) => au::from_px(i.get_size().get_default(Size2D(0,0)).width),
|
||||
TextBox(_,d) => d.run.min_width_for_range(TextRange(d.offset, d.length)),
|
||||
TextBox(_,d) => d.run.min_width_for_range(d.range),
|
||||
UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here."
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +293,7 @@ impl RenderBox : RenderBoxMethods {
|
|||
// factor in min/pref widths of any text runs that it owns.
|
||||
TextBox(_,d) => {
|
||||
let mut max_line_width: au = au(0);
|
||||
for d.run.iter_natural_lines_for_range(TextRange(d.offset, d.length)) |line_range| {
|
||||
for d.run.iter_natural_lines_for_range(d.range) |line_range| {
|
||||
// if the line is a single newline, then len will be zero
|
||||
if line_range.length() == 0 { loop }
|
||||
|
||||
|
@ -442,7 +442,7 @@ impl RenderBox : RenderBoxMethods {
|
|||
UnscannedTextBox(*) => fail ~"Shouldn't see unscanned boxes here.",
|
||||
TextBox(_,d) => {
|
||||
list.append_item(~dl::Text(copy abs_box_bounds, text_run::serialize(builder.ctx.font_cache, d.run),
|
||||
d.offset, d.length))
|
||||
d.range.begin(), d.range.length()))
|
||||
},
|
||||
// TODO: items for background, border, outline
|
||||
GenericBox(_) => {
|
||||
|
@ -519,7 +519,7 @@ impl RenderBox : BoxedDebugMethods {
|
|||
let repr = match self {
|
||||
@GenericBox(*) => ~"GenericBox",
|
||||
@ImageBox(*) => ~"ImageBox",
|
||||
@TextBox(_,d) => fmt!("TextBox(text=%s)", str::substr(d.run.text, d.offset, d.length)),
|
||||
@TextBox(_,d) => fmt!("TextBox(text=%s)", str::substr(d.run.text, d.range.begin(), d.range.length())),
|
||||
@UnscannedTextBox(_,s) => fmt!("UnscannedTextBox(%s)", s)
|
||||
};
|
||||
|
||||
|
|
|
@ -168,7 +168,8 @@ impl TextRunScanner {
|
|||
let run = @TextRun(ctx.font_cache.get_test_font(), move transformed_text);
|
||||
debug!("TextRunScanner: pushing single text box when start=%u,end=%u",
|
||||
self.clump_start, self.clump_end);
|
||||
let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump_start].d(), run, 0, run.text.len());
|
||||
let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump_start].d(), run,
|
||||
TextRange(0, run.text.len()));
|
||||
out_boxes.push(new_box);
|
||||
},
|
||||
(false, true) => {
|
||||
|
@ -221,7 +222,8 @@ impl TextRunScanner {
|
|||
let run = @TextRun(ctx.font_cache.get_test_font(), move run_str);
|
||||
debug!("TextRunScanner: pushing box(es) when start=%u,end=%u",
|
||||
self.clump_start, self.clump_end);
|
||||
let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump_start].d(), run, 0, run.text.len());
|
||||
let new_box = layout::text::adapt_textbox_with_range(in_boxes[self.clump_start].d(), run,
|
||||
TextRange(0, run.text.len()));
|
||||
out_boxes.push(new_box);
|
||||
}
|
||||
} /* /match */
|
||||
|
@ -586,7 +588,7 @@ impl FlowContext : InlineLayout {
|
|||
// adjust bounding box metric to box's horizontal offset
|
||||
// TODO: can we trust the leading provided by font metrics?
|
||||
@TextBox(_, data) => {
|
||||
let text_bounds = data.run.metrics_for_range(TextRange(data.offset, data.length)).bounding_box;
|
||||
let text_bounds = data.run.metrics_for_range(data.range).bounding_box;
|
||||
text_bounds.translate(&Point2D(cur_box.d().position.origin.x, au(0)))
|
||||
},
|
||||
_ => fail fmt!("Tried to compute bounding box of unknown Box variant: %s", cur_box.debug_str())
|
||||
|
|
|
@ -1,34 +1,27 @@
|
|||
/** Text layout. */
|
||||
|
||||
use au = gfx::geometry;
|
||||
use au::au;
|
||||
use geom::size::Size2D;
|
||||
use servo_text::text_run::{TextRange, TextRun};
|
||||
use servo_text::font_cache::FontCache;
|
||||
use layout::box::{TextBox, RenderBox, RenderBoxData, UnscannedTextBox};
|
||||
use layout::context::LayoutContext;
|
||||
|
||||
pub struct TextBoxData {
|
||||
run: @TextRun,
|
||||
offset: uint,
|
||||
length: uint
|
||||
range: TextRange,
|
||||
}
|
||||
|
||||
pub fn TextBoxData(run: @TextRun, offset: uint, length: uint) -> TextBoxData {
|
||||
pub fn TextBoxData(run: @TextRun, range: TextRange) -> TextBoxData {
|
||||
TextBoxData {
|
||||
run: run,
|
||||
offset: offset,
|
||||
length: length
|
||||
range: range,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn adapt_textbox_with_range(box_data: &RenderBoxData, run: @TextRun,
|
||||
offset: uint, length: uint) -> @RenderBox {
|
||||
range: TextRange) -> @RenderBox {
|
||||
debug!("Creating textbox with span: (strlen=%u, off=%u, len=%u) of textrun: %s",
|
||||
run.text.len(), offset, length, run.text);
|
||||
run.text.len(), range.begin(), range.length(), run.text);
|
||||
let new_box_data = copy *box_data;
|
||||
let new_text_data = TextBoxData(run, offset, length);
|
||||
let metrics = run.metrics_for_range(TextRange(offset, length));
|
||||
let new_text_data = TextBoxData(run, range);
|
||||
let metrics = run.metrics_for_range(range);
|
||||
new_box_data.position.size = metrics.bounding_box.size;
|
||||
@TextBox(move new_box_data, move new_text_data)
|
||||
}
|
||||
|
@ -45,58 +38,3 @@ impl RenderBox : UnscannedMethods {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* The main reflow routine for text layout.
|
||||
impl @RenderBox : TextLayout {
|
||||
fn reflow_text(ctx: &LayoutContext) {
|
||||
let d = match self {
|
||||
@TextBox(_,d) => { d }
|
||||
_ => { fail ~"expected text box in reflow_text!" }
|
||||
};
|
||||
|
||||
// TODO: get font from textrun's TextStyle
|
||||
let font = ctx.font_cache.get_test_font();
|
||||
|
||||
// Do line breaking.
|
||||
let mut current = TextRun(font, d.text);
|
||||
let mut lines = dvec::DVec();
|
||||
let mut width_left = au::from_px(800);
|
||||
let mut max_width = au(0);
|
||||
|
||||
while current.size().width > width_left {
|
||||
let min_width = current.min_break_width();
|
||||
|
||||
debug!("line %d, current width %d, width left %d, min width %d",
|
||||
lines.len() as int,
|
||||
*current.size().width as int,
|
||||
*width_left as int,
|
||||
*min_width as int);
|
||||
|
||||
if min_width > width_left {
|
||||
// Too bad, we couldn't break. Overflow.
|
||||
break;
|
||||
}
|
||||
|
||||
let (prev_line, next_line) = current.split(font, width_left);
|
||||
let prev_width = prev_line.size().width;
|
||||
if max_width < prev_width {
|
||||
max_width = prev_width;
|
||||
}
|
||||
|
||||
lines.push(move prev_line);
|
||||
current = next_line;
|
||||
}
|
||||
|
||||
let remaining_width = current.size().width;
|
||||
if max_width < remaining_width {
|
||||
max_width = remaining_width;
|
||||
}
|
||||
|
||||
let line_count = 1 + (lines.len() as i32);
|
||||
let total_height = au(*current.size().height * line_count);
|
||||
lines.push(move current);
|
||||
|
||||
self.d().position.size = Size2D(max_width, total_height);
|
||||
d.runs = move dvec::unwrap(lines);
|
||||
}
|
||||
}*/
|
||||
|
|
|
@ -9,7 +9,7 @@ use glyph::GlyphIndex;
|
|||
use libc::{ c_int, c_double, c_ulong };
|
||||
use native_font::NativeFont;
|
||||
use ptr::{null, addr_of};
|
||||
use text::text_run::TextRun;
|
||||
use text::text_run::{TextRun, TextRange};
|
||||
use vec_to_ptr = vec::raw::to_ptr;
|
||||
|
||||
// Used to abstract over the shaper's choice of fixed int representation.
|
||||
|
@ -41,7 +41,7 @@ struct RunMetrics {
|
|||
|
||||
// Public API
|
||||
pub trait FontMethods {
|
||||
fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics;
|
||||
fn measure_text(&TextRun, TextRange) -> RunMetrics;
|
||||
|
||||
fn buf(&self) -> @~[u8];
|
||||
// these are used to get glyphs and advances in the case that the
|
||||
|
@ -51,15 +51,14 @@ pub trait FontMethods {
|
|||
}
|
||||
|
||||
pub impl Font : FontMethods {
|
||||
fn measure_text(run: &TextRun, offset: uint, length: uint) -> RunMetrics {
|
||||
assert offset < run.text.len();
|
||||
assert offset + length <= run.text.len();
|
||||
fn measure_text(run: &TextRun, range: TextRange) -> RunMetrics {
|
||||
assert range.is_valid_for_string(run.text);
|
||||
|
||||
// TODO: alter advance direction for RTL
|
||||
// TODO(Issue #98): using inter-char and inter-word spacing settings when measuring text
|
||||
let mut advance = au(0);
|
||||
if length > 0 {
|
||||
do run.glyphs.iter_glyphs_for_range(offset, length) |_i, glyph| {
|
||||
if range.length() > 0 {
|
||||
do run.glyphs.iter_glyphs_for_range(range.begin(), range.length()) |_i, glyph| {
|
||||
advance += glyph.advance();
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +74,7 @@ pub impl Font : FontMethods {
|
|||
ascent: self.metrics.ascent,
|
||||
descent: self.metrics.descent,
|
||||
};
|
||||
debug!("Measured text range '%s' with metrics:", run.text.substr(offset, length));
|
||||
debug!("Measured text range '%s' with metrics:", run.text.substr(range.begin(), range.length()));
|
||||
debug!("%?", metrics);
|
||||
|
||||
return metrics;
|
||||
|
|
|
@ -167,7 +167,7 @@ impl TextRun : TextRunMethods {
|
|||
}
|
||||
|
||||
fn metrics_for_range(&self, range: TextRange) -> RunMetrics {
|
||||
self.font.measure_text(self, range.begin(), range.length())
|
||||
self.font.measure_text(self, range)
|
||||
}
|
||||
|
||||
fn min_width_for_range(&self, range: TextRange) -> au {
|
||||
|
@ -175,7 +175,7 @@ impl TextRun : TextRunMethods {
|
|||
|
||||
let mut max_piece_width = au(0);
|
||||
for self.iter_indivisible_pieces_for_range(range) |piece_range| {
|
||||
let metrics = self.font.measure_text(self, piece_range.begin(), piece_range.length());
|
||||
let metrics = self.font.measure_text(self, piece_range);
|
||||
max_piece_width = au::max(max_piece_width, metrics.advance_width);
|
||||
}
|
||||
return max_piece_width;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue