From 6859730f7a5dab1fdbe24325fa7f91d4b4bc1a41 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 14 Sep 2012 15:29:32 -0700 Subject: [PATCH] Another attempt at computing the minimum breaking width for TextRuns --- src/servo/gfx/geometry.rs | 15 ++++ src/servo/text/text_run.rs | 136 +++++++++++++++++++++++++++++++------ 2 files changed, 131 insertions(+), 20 deletions(-) diff --git a/src/servo/gfx/geometry.rs b/src/servo/gfx/geometry.rs index d7a8733049e..6184f19f7b8 100644 --- a/src/servo/gfx/geometry.rs +++ b/src/servo/gfx/geometry.rs @@ -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(x: A, y: A, w: A, h: A) -> Rect { Rect(Point2D(x, y), Size2D(w, h)) } diff --git a/src/servo/text/text_run.rs b/src/servo/text/text_run.rs index d371bf340b3..defff9233fb 100644 --- a/src/servo/text/text_run.rs +++ b/src/servo/text/text_run.rs @@ -11,28 +11,24 @@ use shaper::shape_text; struct TextRun { priv glyphs: ~[Glyph], priv size_: Size2D, - priv min_width_: au, + priv min_break_width_: au, } impl TextRun { + /// The size of the entire TextRun fn size() -> Size2D { self.size_ } - fn preferred_width() -> au { self.size_.width } - fn min_width() -> au { self.min_width_ } + fn min_break_width() -> au { self.min_break_width_ } } fn TextRun(font: Font, text: ~str) -> TextRun { let glyphs = shape_text(&font, text); let size = glyph_run_size(glyphs); - - let min_width = match calc_min_width(&font, text) { - Some(w) => w, - None => size.width - }; + let min_break_width = calc_min_break_width(&font, text); TextRun { glyphs: shape_text(&font, text), size_: size, - min_width_: min_width + min_break_width_: min_break_width } } @@ -48,31 +44,131 @@ fn glyph_run_size(glyphs: &[Glyph]) -> Size2D { return Size2D(pen_end.x, pen_end.y); } -/// If there are breaking opportunities inside a string, then -/// returns the width of the text up to the first break. Otherwise None. -fn calc_min_width(font: &Font, text: &str) -> Option { - None +/// Discovers the width of the largest indivisible substring +fn calc_min_break_width(font: &Font, text: &str) -> au { + let mut max_piece_width = au(0); + 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] -#[ignore] -fn test_calc_min_width_with_breaking() { +fn test_calc_min_break_width1() { let flib = FontLibrary(); let font = flib.get_test_font(); - let actual = calc_min_width(font, ~"firecracker yumyum"); - let expected = Some(px_to_au(84)); + let actual = calc_min_break_width(font, ~"firecracker"); + let expected = px_to_au(84); assert expected == actual; } #[test] -fn test_calc_min_width_without_breaking() { +fn test_calc_min_break_width2() { let flib = FontLibrary(); let font = flib.get_test_font(); - let actual = calc_min_width(font, ~"firecracker_yumyum"); - let expected = None; + let actual = calc_min_break_width(font, ~"firecracker yumyum"); + let expected = px_to_au(84); 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() { #[test]; #[ignore(cfg(target_os = "macos"))];