mirror of
https://github.com/servo/servo.git
synced 2025-08-07 14:35:33 +01:00
Another attempt at computing the minimum breaking width for TextRuns
This commit is contained in:
parent
ddcc11069e
commit
6859730f7a
2 changed files with 131 additions and 20 deletions
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"))];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue