Another attempt at computing the minimum breaking width for TextRuns

This commit is contained in:
Brian Anderson 2012-09-14 15:29:32 -07:00
parent ddcc11069e
commit 6859730f7a
2 changed files with 131 additions and 20 deletions

View file

@ -28,6 +28,21 @@ impl au : cmp::Eq {
} }
} }
impl au : cmp::Ord {
pure fn lt(&&other: au) -> bool {
*self < *other
}
pure fn le(&&other: au) -> bool {
*self <= *other
}
pure fn ge(&&other: au) -> bool {
*self >= *other
}
pure fn gt(&&other: au) -> bool {
*self > *other
}
}
fn box<A:Copy Num>(x: A, y: A, w: A, h: A) -> Rect<A> { fn box<A:Copy Num>(x: A, y: A, w: A, h: A) -> Rect<A> {
Rect(Point2D(x, y), Size2D(w, h)) Rect(Point2D(x, y), Size2D(w, h))
} }

View file

@ -11,28 +11,24 @@ use shaper::shape_text;
struct TextRun { struct TextRun {
priv glyphs: ~[Glyph], priv glyphs: ~[Glyph],
priv size_: Size2D<au>, priv size_: Size2D<au>,
priv min_width_: au, priv min_break_width_: au,
} }
impl TextRun { impl TextRun {
/// The size of the entire TextRun
fn size() -> Size2D<au> { self.size_ } fn size() -> Size2D<au> { self.size_ }
fn preferred_width() -> au { self.size_.width } fn min_break_width() -> au { self.min_break_width_ }
fn min_width() -> au { self.min_width_ }
} }
fn TextRun(font: Font, text: ~str) -> TextRun { fn TextRun(font: Font, text: ~str) -> TextRun {
let glyphs = shape_text(&font, text); let glyphs = shape_text(&font, text);
let size = glyph_run_size(glyphs); let size = glyph_run_size(glyphs);
let min_break_width = calc_min_break_width(&font, text);
let min_width = match calc_min_width(&font, text) {
Some(w) => w,
None => size.width
};
TextRun { TextRun {
glyphs: shape_text(&font, text), glyphs: shape_text(&font, text),
size_: size, size_: size,
min_width_: min_width min_break_width_: min_break_width
} }
} }
@ -48,31 +44,131 @@ fn glyph_run_size(glyphs: &[Glyph]) -> Size2D<au> {
return Size2D(pen_end.x, pen_end.y); return Size2D(pen_end.x, pen_end.y);
} }
/// If there are breaking opportunities inside a string, then /// Discovers the width of the largest indivisible substring
/// returns the width of the text up to the first break. Otherwise None. fn calc_min_break_width(font: &Font, text: &str) -> au {
fn calc_min_width(font: &Font, text: &str) -> Option<au> { let mut max_piece_width = au(0);
None do iter_indivisible_slices(font, text) |slice| {
let glyphs = shape_text(font, slice);
let size = glyph_run_size(glyphs);
if size.width > max_piece_width {
max_piece_width = size.width
}
}
return max_piece_width;
}
/// Iterates over all the indivisible substrings
fn iter_indivisible_slices(font: &Font, text: &r/str,
f: fn((&r/str))) {
let mut curr = text;
loop {
match str::find(curr, |c| !char::is_whitespace(c) ) {
Some(idx) => {
curr = str::view(curr, idx, curr.len());
}
None => {
// Everything else is whitespace
break
}
}
match str::find(curr, |c| char::is_whitespace(c) ) {
Some(idx) => {
let piece = str::view(curr, 0, idx);
f(piece);
curr = str::view(curr, idx, curr.len());
}
None => {
assert curr.is_not_empty();
f(curr);
// This is the end of the string
break;
}
}
}
} }
#[test] #[test]
#[ignore] fn test_calc_min_break_width1() {
fn test_calc_min_width_with_breaking() {
let flib = FontLibrary(); let flib = FontLibrary();
let font = flib.get_test_font(); let font = flib.get_test_font();
let actual = calc_min_width(font, ~"firecracker yumyum"); let actual = calc_min_break_width(font, ~"firecracker");
let expected = Some(px_to_au(84)); let expected = px_to_au(84);
assert expected == actual; assert expected == actual;
} }
#[test] #[test]
fn test_calc_min_width_without_breaking() { fn test_calc_min_break_width2() {
let flib = FontLibrary(); let flib = FontLibrary();
let font = flib.get_test_font(); let font = flib.get_test_font();
let actual = calc_min_width(font, ~"firecracker_yumyum"); let actual = calc_min_break_width(font, ~"firecracker yumyum");
let expected = None; let expected = px_to_au(84);
assert expected == actual; assert expected == actual;
} }
#[test]
fn test_calc_min_break_width3() {
let flib = FontLibrary();
let font = flib.get_test_font();
let actual = calc_min_break_width(font, ~"yumyum firecracker");
let expected = px_to_au(84);
assert expected == actual;
}
#[test]
fn test_calc_min_break_width4() {
let flib = FontLibrary();
let font = flib.get_test_font();
let actual = calc_min_break_width(font, ~"yumyum firecracker yumyum");
let expected = px_to_au(84);
assert expected == actual;
}
#[test]
fn test_iter_indivisible_slices() {
let flib = FontLibrary();
let font = flib.get_test_font();
let mut slices = ~[];
do iter_indivisible_slices(font, "firecracker yumyum woopwoop") |slice| {
slices += [slice];
}
assert slices == ~["firecracker", "yumyum", "woopwoop"];
}
#[test]
fn test_iter_indivisible_slices_trailing_whitespace() {
let flib = FontLibrary();
let font = flib.get_test_font();
let mut slices = ~[];
do iter_indivisible_slices(font, "firecracker ") |slice| {
slices += [slice];
}
assert slices == ~["firecracker"];
}
#[test]
fn test_iter_indivisible_slices_leading_whitespace() {
let flib = FontLibrary();
let font = flib.get_test_font();
let mut slices = ~[];
do iter_indivisible_slices(font, " firecracker") |slice| {
slices += [slice];
}
assert slices == ~["firecracker"];
}
#[test]
fn test_iter_indivisible_slices_empty() {
let flib = FontLibrary();
let font = flib.get_test_font();
let mut slices = ~[];
do iter_indivisible_slices(font, "") |slice| {
slices += [slice];
}
assert slices == ~[];
}
fn should_calculate_the_total_size() { fn should_calculate_the_total_size() {
#[test]; #[test];
#[ignore(cfg(target_os = "macos"))]; #[ignore(cfg(target_os = "macos"))];