From e98bd15de6d40c61df2949021cecd46c11a079e9 Mon Sep 17 00:00:00 2001 From: Michael Oswald Date: Wed, 10 Apr 2024 17:46:21 +0200 Subject: [PATCH 1/6] Fixed UTF-8 issue in layout_multiline_text --- .gitignore | 18 ++++++++ plotters/src/element/text.rs | 86 +++++++++++++++++++++++++++++++----- 2 files changed, 92 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 269016ca..a82a3ef7 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,21 @@ .vscode/* Cargo.lock .idea +plotters/area_series.svg +plotters/chart_builder_on.svg +plotters/composable.svg +plotters/configure_axes.svg +plotters/configure_series_labels.svg +plotters/cuboid.svg +plotters/error_bars_vertical.svg +plotters/font_desc_color.svg +plotters/histogram_vertical.svg +plotters/into_text_style.svg +plotters/label_area_position.svg +plotters/line_series_point_size.svg +plotters/shape_style_filled.svg +plotters/shape_style_stroke_width.svg +plotters/surface_series_style_func.svg +plotters/surface_series_xoz.svg +plotters/with_anchor.svg +plotters/with_color.svg diff --git a/plotters/src/element/text.rs b/plotters/src/element/text.rs index ca813c7c..21b79e41 100644 --- a/plotters/src/element/text.rs +++ b/plotters/src/element/text.rs @@ -126,32 +126,94 @@ fn layout_multiline_text<'a, F: FnMut(&'a str)>( if max_width == 0 || line.is_empty() { func(line); } else { - let mut remaining = &line[0..]; + let mut indices = line.char_indices().map(|(idx, _)| idx).peekable(); + let font2 = font.clone(); - while !remaining.is_empty() { - let mut left = 0; - while left < remaining.len() { - let width = font.box_size(&remaining[0..=left]).unwrap_or((0, 0)).0 as i32; + let it = std::iter::from_fn(|| { + let start_idx = match indices.next() { + Some(idx) => idx, + None => return None, + }; + // iterate over indices + while let Some(idx) = indices.next() { + let substring = &line[start_idx..idx]; + let width = font2.box_size(substring).unwrap_or((0, 0)).0 as i32; if width > max_width as i32 { break; } - left += 1; } - if left == 0 { - left += 1; - } + let end_idx = match indices.peek() { + Some(idx) => *idx, + None => line.bytes().len(), + }; - let cur_line = &remaining[..left]; - remaining = &remaining[left..]; + Some(&line[start_idx..end_idx]) + }); - func(cur_line); + for chunk in it { + func(chunk); } } } } +#[cfg(test)] +#[test] +fn test_multi_layout() { + use plotters_backend::{FontFamily, FontStyle}; + + let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold); + + layout_multiline_text("öäabcde", 40, font, |txt| { + println!("Got: {}", txt); + assert!(txt == "öäabc" || txt == "de"); + }); + + let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold); + layout_multiline_text("öä", 40, font, |txt| { + println!("Got: {}", txt); + assert_eq!(txt, "öä") + }); +} + +// fn layout_multiline_text<'a, F: FnMut(&'a str)>( +// text: &'a str, +// max_width: u32, +// font: FontDesc<'a>, +// mut func: F, +// ) { +// for line in text.lines() { +// if max_width == 0 || line.is_empty() { +// func(line); +// } else { +// let mut remaining = &line[0..]; + +// while !remaining.is_empty() { +// let mut left = 0; +// while left < remaining.len() { +// let width = font.box_size(&remaining[0..=left]).unwrap_or((0, 0)).0 as i32; + +// if width > max_width as i32 { +// break; +// } +// left += 1; +// } + +// if left == 0 { +// left += 1; +// } + +// let cur_line = &remaining[..left]; +// remaining = &remaining[left..]; + +// func(cur_line); +// } +// } +// } +// } + impl<'a, T: Borrow> MultiLineText<'a, BackendCoord, T> { /// Compute the line layout pub fn compute_line_layout(&self) -> FontResult> { From fd87ad945968ed439e05304f43631ec0b3b03a89 Mon Sep 17 00:00:00 2001 From: Michael Oswald Date: Wed, 10 Apr 2024 17:51:00 +0200 Subject: [PATCH 2/6] Added comments --- plotters/src/element/text.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/plotters/src/element/text.rs b/plotters/src/element/text.rs index 21b79e41..906e0f52 100644 --- a/plotters/src/element/text.rs +++ b/plotters/src/element/text.rs @@ -116,6 +116,11 @@ impl<'a, Coord, T: Borrow> MultiLineText<'a, Coord, T> { } } + +// Rewrite of the layout function for multiline-text. It crashes when UTF-8 is used +// instead of ASCII. Solution taken from: +// https://stackoverflow.com/questions/68122526/splitting-a-utf-8-string-into-chunks +// and modified for our purposes. fn layout_multiline_text<'a, F: FnMut(&'a str)>( text: &'a str, max_width: u32, From 77d29464f84f4750c0812b13b63447688ff8c536 Mon Sep 17 00:00:00 2001 From: Michael Oswald Date: Sat, 13 Apr 2024 12:16:01 +0200 Subject: [PATCH 3/6] Corrected after executing test suite --- plotters/src/element/text.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/plotters/src/element/text.rs b/plotters/src/element/text.rs index 906e0f52..4c06ff40 100644 --- a/plotters/src/element/text.rs +++ b/plotters/src/element/text.rs @@ -165,6 +165,7 @@ fn layout_multiline_text<'a, F: FnMut(&'a str)>( } #[cfg(test)] +#[cfg(ttf)] #[test] fn test_multi_layout() { use plotters_backend::{FontFamily, FontStyle}; @@ -177,7 +178,9 @@ fn test_multi_layout() { }); let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold); - layout_multiline_text("öä", 40, font, |txt| { + layout_multiline_text("öä", 100, font, |txt| { + // This does not divide the line, but still crashed in the previous implementation + // of layout_multiline_text. So this test should be reliable println!("Got: {}", txt); assert_eq!(txt, "öä") }); From 5a8554146267e066cfd1a9c88ba3d93ae296a681 Mon Sep 17 00:00:00 2001 From: Michael Oswald Date: Sat, 13 Apr 2024 12:29:43 +0200 Subject: [PATCH 4/6] Fixed test to work with features --- plotters/src/element/text.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/plotters/src/element/text.rs b/plotters/src/element/text.rs index 4c06ff40..de496612 100644 --- a/plotters/src/element/text.rs +++ b/plotters/src/element/text.rs @@ -164,8 +164,7 @@ fn layout_multiline_text<'a, F: FnMut(&'a str)>( } } -#[cfg(test)] -#[cfg(ttf)] +#[cfg(feature = "ttf")] #[test] fn test_multi_layout() { use plotters_backend::{FontFamily, FontStyle}; From a22f7b966ef09821d31a820ac2037d9515c36059 Mon Sep 17 00:00:00 2001 From: Michael Oswald Date: Sat, 13 Apr 2024 12:30:17 +0200 Subject: [PATCH 5/6] Removed commented original function --- plotters/src/element/text.rs | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/plotters/src/element/text.rs b/plotters/src/element/text.rs index de496612..a4382c01 100644 --- a/plotters/src/element/text.rs +++ b/plotters/src/element/text.rs @@ -185,42 +185,6 @@ fn test_multi_layout() { }); } -// fn layout_multiline_text<'a, F: FnMut(&'a str)>( -// text: &'a str, -// max_width: u32, -// font: FontDesc<'a>, -// mut func: F, -// ) { -// for line in text.lines() { -// if max_width == 0 || line.is_empty() { -// func(line); -// } else { -// let mut remaining = &line[0..]; - -// while !remaining.is_empty() { -// let mut left = 0; -// while left < remaining.len() { -// let width = font.box_size(&remaining[0..=left]).unwrap_or((0, 0)).0 as i32; - -// if width > max_width as i32 { -// break; -// } -// left += 1; -// } - -// if left == 0 { -// left += 1; -// } - -// let cur_line = &remaining[..left]; -// remaining = &remaining[left..]; - -// func(cur_line); -// } -// } -// } -// } - impl<'a, T: Borrow> MultiLineText<'a, BackendCoord, T> { /// Compute the line layout pub fn compute_line_layout(&self) -> FontResult> { From c523bec2b91a74abc770cf180e2533e3ad999827 Mon Sep 17 00:00:00 2001 From: Michael Oswald Date: Thu, 18 Apr 2024 19:12:40 +0200 Subject: [PATCH 6/6] Put glob on svg files in .gitignore --- .gitignore | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/.gitignore b/.gitignore index a82a3ef7..297134f4 100644 --- a/.gitignore +++ b/.gitignore @@ -4,21 +4,4 @@ .vscode/* Cargo.lock .idea -plotters/area_series.svg -plotters/chart_builder_on.svg -plotters/composable.svg -plotters/configure_axes.svg -plotters/configure_series_labels.svg -plotters/cuboid.svg -plotters/error_bars_vertical.svg -plotters/font_desc_color.svg -plotters/histogram_vertical.svg -plotters/into_text_style.svg -plotters/label_area_position.svg -plotters/line_series_point_size.svg -plotters/shape_style_filled.svg -plotters/shape_style_stroke_width.svg -plotters/surface_series_style_func.svg -plotters/surface_series_xoz.svg -plotters/with_anchor.svg -plotters/with_color.svg +plotters/*.svg