mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Convert offset+length to TextRange in parts of TextRun API.
This commit is contained in:
parent
e2c5bcaf37
commit
2cbfde7683
4 changed files with 86 additions and 50 deletions
|
@ -22,7 +22,7 @@ use layout::debug::BoxedDebugMethods;
|
|||
use layout::flow::FlowContext;
|
||||
use layout::text::TextBoxData;
|
||||
use servo_text::text_run;
|
||||
use servo_text::text_run::TextRun;
|
||||
use servo_text::text_run::{TextRange, TextRun};
|
||||
use std::net::url::Url;
|
||||
use task::spawn;
|
||||
use util::color::Color;
|
||||
|
@ -193,16 +193,16 @@ impl RenderBox : RenderBoxMethods {
|
|||
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(TextRange(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(TextRange(off, len));
|
||||
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(off, len) {
|
||||
if starts_line && i == 0 && data.run.range_is_trimmable_whitespace(TextRange(off, len)) {
|
||||
debug!("split_to_width: case=skipping leading trimmable whitespace");
|
||||
left_offset += len;
|
||||
} else {
|
||||
|
@ -213,7 +213,7 @@ impl RenderBox : RenderBoxMethods {
|
|||
} else { /* advance > remaining_width */
|
||||
should_continue = false;
|
||||
|
||||
if data.run.range_is_trimmable_whitespace(off, len) {
|
||||
if data.run.range_is_trimmable_whitespace(TextRange(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");
|
||||
|
@ -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(d.offset, d.length),
|
||||
TextBox(_,d) => d.run.min_width_for_range(TextRange(d.offset, d.length)),
|
||||
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(d.offset, d.length) |line_offset, line_len| {
|
||||
for d.run.iter_natural_lines_for_range(TextRange(d.offset, d.length)) |line_offset, line_len| {
|
||||
// if the line is a single newline, then len will be zero
|
||||
if line_len == 0 { loop }
|
||||
|
||||
|
|
|
@ -586,7 +586,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(data.offset, data.length).bounding_box;
|
||||
let text_bounds = data.run.metrics_for_range(TextRange(data.offset, data.length)).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())
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
use au = gfx::geometry;
|
||||
use au::au;
|
||||
use geom::size::Size2D;
|
||||
use servo_text::text_run::TextRun;
|
||||
use servo_text::text_run::{TextRange, TextRun};
|
||||
use servo_text::font_cache::FontCache;
|
||||
use layout::box::{TextBox, RenderBox, RenderBoxData, UnscannedTextBox};
|
||||
use layout::context::LayoutContext;
|
||||
|
@ -28,7 +28,7 @@ pub fn adapt_textbox_with_range(box_data: &RenderBoxData, run: @TextRun,
|
|||
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);
|
||||
let metrics = run.metrics_for_range(TextRange(offset, length));
|
||||
new_box_data.position.size = metrics.bounding_box.size;
|
||||
@TextBox(move new_box_data, move new_text_data)
|
||||
}
|
||||
|
|
|
@ -19,6 +19,50 @@ pub struct TextRun {
|
|||
priv glyphs: GlyphStore,
|
||||
}
|
||||
|
||||
pub struct TextRange {
|
||||
priv off: u16,
|
||||
priv len: u16
|
||||
}
|
||||
|
||||
pure fn TextRange(off: uint, len :uint) -> TextRange {
|
||||
assert off <= u16::max_value as uint;
|
||||
assert len <= u16::max_value as uint;
|
||||
|
||||
TextRange {
|
||||
off: off as u16,
|
||||
len: len as u16
|
||||
}
|
||||
}
|
||||
|
||||
impl TextRange {
|
||||
pub pure fn begin() -> uint { self.off as uint }
|
||||
pub pure fn length() -> uint { self.len as uint }
|
||||
pub pure fn end() -> uint { (self.off as uint) + (self.len as uint) }
|
||||
|
||||
pub pure fn eachi(cb: fn&(uint) -> bool) {
|
||||
do uint::range(self.off as uint,
|
||||
(self.off as uint) + (self.len as uint)) |i| {
|
||||
cb(i)
|
||||
}
|
||||
}
|
||||
|
||||
pub pure fn is_valid_for_string(s: &str) -> bool {
|
||||
self.begin() < s.len() && self.end() <= s.len() && self.length() <= s.len()
|
||||
}
|
||||
|
||||
pub pure fn shift(i: int) -> TextRange {
|
||||
TextRange(((self.off as int) + i) as uint, self.len as uint)
|
||||
}
|
||||
|
||||
pub pure fn extend(i: int) -> TextRange {
|
||||
TextRange(self.off as uint, ((self.len as int) + i) as uint)
|
||||
}
|
||||
|
||||
pub pure fn adjust(off_i: int, len_i: int) -> TextRange {
|
||||
TextRange(((self.off as int) + off_i) as uint, ((self.len as int) + len_i) as uint)
|
||||
}
|
||||
}
|
||||
|
||||
// This is a hack until TextRuns are normally sendable, or
|
||||
// we instead use ARC<TextRun> everywhere.
|
||||
pub struct SendableTextRun {
|
||||
|
@ -47,22 +91,23 @@ pub fn deserialize(cache: @FontCache, run: &SendableTextRun) -> @TextRun {
|
|||
|
||||
trait TextRunMethods {
|
||||
pure fn glyphs(&self) -> &self/GlyphStore;
|
||||
pure fn iter_indivisible_pieces_for_range(&self, offset: uint, length: uint, f: fn(uint, uint) -> bool);
|
||||
pure fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool);
|
||||
// TODO: needs to take box style as argument, or move to TextBox.
|
||||
// see Gecko's IsTrimmableSpace methods for details.
|
||||
pure fn range_is_trimmable_whitespace(&self, offset: uint, length: uint) -> bool;
|
||||
pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool;
|
||||
|
||||
fn metrics_for_range(offset: uint, length: uint) -> RunMetrics;
|
||||
fn min_width_for_range(offset: uint, length: uint) -> au;
|
||||
fn iter_natural_lines_for_range(&self, offset: uint, length: uint, f: fn(uint, uint) -> bool);
|
||||
fn metrics_for_range(&self, range: TextRange) -> RunMetrics;
|
||||
fn min_width_for_range(&self, range: TextRange) -> au;
|
||||
fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool);
|
||||
}
|
||||
|
||||
impl TextRun : TextRunMethods {
|
||||
pure fn glyphs(&self) -> &self/GlyphStore { &self.glyphs }
|
||||
|
||||
pure fn range_is_trimmable_whitespace(&self, offset: uint, length: uint) -> bool {
|
||||
let mut i = offset;
|
||||
while i < offset + length {
|
||||
pure fn range_is_trimmable_whitespace(&self, range: TextRange) -> bool {
|
||||
let mut i = range.begin();
|
||||
while i < range.end() {
|
||||
// jump i to each new char
|
||||
let {ch, next} = str::char_range_at(self.text, i);
|
||||
match ch {
|
||||
' ' | '\t' | '\r' => {},
|
||||
|
@ -73,37 +118,30 @@ impl TextRun : TextRunMethods {
|
|||
return true;
|
||||
}
|
||||
|
||||
fn metrics_for_range(offset: uint, length: uint) -> RunMetrics {
|
||||
self.font.measure_text(&self, offset, length)
|
||||
fn metrics_for_range(&self, range: TextRange) -> RunMetrics {
|
||||
self.font.measure_text(self, range.begin(), range.length())
|
||||
}
|
||||
|
||||
fn min_width_for_range(offset: uint, length: uint) -> au {
|
||||
assert length > 0;
|
||||
assert offset < self.text.len();
|
||||
assert offset + length <= self.text.len();
|
||||
fn min_width_for_range(&self, range: TextRange) -> au {
|
||||
assert range.is_valid_for_string(self.text);
|
||||
|
||||
let mut max_piece_width = au(0);
|
||||
for self.iter_indivisible_pieces_for_range(offset, length) |piece_offset, piece_len| {
|
||||
let metrics = self.font.measure_text(&self, piece_offset, piece_len);
|
||||
if metrics.advance_width > max_piece_width {
|
||||
max_piece_width = metrics.advance_width;
|
||||
}
|
||||
};
|
||||
|
||||
for self.iter_indivisible_pieces_for_range(range) |piece_offset, piece_len| {
|
||||
let metrics = self.font.measure_text(self, piece_offset, piece_len);
|
||||
max_piece_width = au::max(max_piece_width, metrics.advance_width);
|
||||
}
|
||||
return max_piece_width;
|
||||
}
|
||||
|
||||
fn iter_natural_lines_for_range(&self, offset: uint, length: uint, f: fn(uint, uint) -> bool) {
|
||||
assert length > 0;
|
||||
assert offset < self.text.len();
|
||||
assert offset + length <= self.text.len();
|
||||
fn iter_natural_lines_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) {
|
||||
assert range.is_valid_for_string(self.text);
|
||||
|
||||
let mut clump_offset = offset;
|
||||
let mut clump_offset = range.begin();
|
||||
let mut clump_length = 0;
|
||||
let mut in_clump = false;
|
||||
|
||||
// clump non-linebreaks of nonzero length
|
||||
for uint::range(offset, offset + length) |i| {
|
||||
for range.eachi |i| {
|
||||
match (self.glyphs.char_is_newline(i), in_clump) {
|
||||
(false, true) => { clump_length += 1; }
|
||||
(false, false) => { in_clump = true; clump_offset = i; clump_length = 1; }
|
||||
|
@ -119,17 +157,15 @@ impl TextRun : TextRunMethods {
|
|||
|
||||
// flush any remaining chars as a line
|
||||
if in_clump {
|
||||
clump_length = (offset + length) - clump_offset;
|
||||
clump_length = range.end() - clump_offset;
|
||||
f(clump_offset, clump_length);
|
||||
}
|
||||
}
|
||||
|
||||
pure fn iter_indivisible_pieces_for_range(&self, offset: uint, length: uint, f: fn(uint, uint) -> bool) {
|
||||
assert length > 0;
|
||||
assert offset < self.text.len();
|
||||
assert offset + length <= self.text.len();
|
||||
pure fn iter_indivisible_pieces_for_range(&self, range: TextRange, f: fn(uint, uint) -> bool) {
|
||||
assert range.is_valid_for_string(self.text);
|
||||
|
||||
let mut clump_offset = offset;
|
||||
let mut clump_offset = range.begin();
|
||||
let mut clump_length;
|
||||
|
||||
loop {
|
||||
|
@ -140,12 +176,12 @@ impl TextRun : TextRunMethods {
|
|||
if !f(clump_offset, clump_length) { break }
|
||||
clump_offset += clump_length;
|
||||
// reached end
|
||||
if clump_offset == offset + length { break }
|
||||
if clump_offset == range.end() { break }
|
||||
},
|
||||
None => {
|
||||
// nothing left, flush last piece containing only whitespace
|
||||
if clump_offset < offset + length {
|
||||
let clump_length = (offset + length) - clump_offset;
|
||||
if clump_offset < range.end() {
|
||||
let clump_length = range.end() - clump_offset;
|
||||
f(clump_offset, clump_length);
|
||||
}
|
||||
break
|
||||
|
@ -159,12 +195,12 @@ impl TextRun : TextRunMethods {
|
|||
if !f(clump_offset, clump_length) { break }
|
||||
clump_offset += clump_length;
|
||||
// reached end
|
||||
if clump_offset == offset + length { break }
|
||||
if clump_offset == range.end() { break }
|
||||
}
|
||||
None => {
|
||||
// nothing left, flush last piece containing only non-whitespaces
|
||||
if clump_offset < offset + length {
|
||||
let clump_length = (offset + length) - clump_offset;
|
||||
if clump_offset < range.end() {
|
||||
let clump_length = range.end() - clump_offset;
|
||||
f(clump_offset, clump_length);
|
||||
}
|
||||
break
|
||||
|
@ -214,7 +250,7 @@ fn test_iter_indivisible_pieces() {
|
|||
let font = flib.get_test_font();
|
||||
let run = TextRun(font, copy text);
|
||||
let mut slices : ~[~str] = ~[];
|
||||
for run.iter_indivisible_pieces_for_range(0, text.len()) |offset, length| {
|
||||
for run.iter_indivisible_pieces_for_range(TextRange(0, text.len())) |offset, length| {
|
||||
slices.push(str::slice(text, offset, length));
|
||||
}
|
||||
assert slices == res;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue