Skip to content

Commit e98bd15

Browse files
committed
Fixed UTF-8 issue in layout_multiline_text
1 parent d15b0c0 commit e98bd15

File tree

2 files changed

+92
-12
lines changed

2 files changed

+92
-12
lines changed

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,21 @@
44
.vscode/*
55
Cargo.lock
66
.idea
7+
plotters/area_series.svg
8+
plotters/chart_builder_on.svg
9+
plotters/composable.svg
10+
plotters/configure_axes.svg
11+
plotters/configure_series_labels.svg
12+
plotters/cuboid.svg
13+
plotters/error_bars_vertical.svg
14+
plotters/font_desc_color.svg
15+
plotters/histogram_vertical.svg
16+
plotters/into_text_style.svg
17+
plotters/label_area_position.svg
18+
plotters/line_series_point_size.svg
19+
plotters/shape_style_filled.svg
20+
plotters/shape_style_stroke_width.svg
21+
plotters/surface_series_style_func.svg
22+
plotters/surface_series_xoz.svg
23+
plotters/with_anchor.svg
24+
plotters/with_color.svg

plotters/src/element/text.rs

Lines changed: 74 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -126,32 +126,94 @@ fn layout_multiline_text<'a, F: FnMut(&'a str)>(
126126
if max_width == 0 || line.is_empty() {
127127
func(line);
128128
} else {
129-
let mut remaining = &line[0..];
129+
let mut indices = line.char_indices().map(|(idx, _)| idx).peekable();
130+
let font2 = font.clone();
130131

131-
while !remaining.is_empty() {
132-
let mut left = 0;
133-
while left < remaining.len() {
134-
let width = font.box_size(&remaining[0..=left]).unwrap_or((0, 0)).0 as i32;
132+
let it = std::iter::from_fn(|| {
133+
let start_idx = match indices.next() {
134+
Some(idx) => idx,
135+
None => return None,
136+
};
135137

138+
// iterate over indices
139+
while let Some(idx) = indices.next() {
140+
let substring = &line[start_idx..idx];
141+
let width = font2.box_size(substring).unwrap_or((0, 0)).0 as i32;
136142
if width > max_width as i32 {
137143
break;
138144
}
139-
left += 1;
140145
}
141146

142-
if left == 0 {
143-
left += 1;
144-
}
147+
let end_idx = match indices.peek() {
148+
Some(idx) => *idx,
149+
None => line.bytes().len(),
150+
};
145151

146-
let cur_line = &remaining[..left];
147-
remaining = &remaining[left..];
152+
Some(&line[start_idx..end_idx])
153+
});
148154

149-
func(cur_line);
155+
for chunk in it {
156+
func(chunk);
150157
}
151158
}
152159
}
153160
}
154161

162+
#[cfg(test)]
163+
#[test]
164+
fn test_multi_layout() {
165+
use plotters_backend::{FontFamily, FontStyle};
166+
167+
let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold);
168+
169+
layout_multiline_text("öäabcde", 40, font, |txt| {
170+
println!("Got: {}", txt);
171+
assert!(txt == "öäabc" || txt == "de");
172+
});
173+
174+
let font = FontDesc::new(FontFamily::SansSerif, 20 as f64, FontStyle::Bold);
175+
layout_multiline_text("öä", 40, font, |txt| {
176+
println!("Got: {}", txt);
177+
assert_eq!(txt, "öä")
178+
});
179+
}
180+
181+
// fn layout_multiline_text<'a, F: FnMut(&'a str)>(
182+
// text: &'a str,
183+
// max_width: u32,
184+
// font: FontDesc<'a>,
185+
// mut func: F,
186+
// ) {
187+
// for line in text.lines() {
188+
// if max_width == 0 || line.is_empty() {
189+
// func(line);
190+
// } else {
191+
// let mut remaining = &line[0..];
192+
193+
// while !remaining.is_empty() {
194+
// let mut left = 0;
195+
// while left < remaining.len() {
196+
// let width = font.box_size(&remaining[0..=left]).unwrap_or((0, 0)).0 as i32;
197+
198+
// if width > max_width as i32 {
199+
// break;
200+
// }
201+
// left += 1;
202+
// }
203+
204+
// if left == 0 {
205+
// left += 1;
206+
// }
207+
208+
// let cur_line = &remaining[..left];
209+
// remaining = &remaining[left..];
210+
211+
// func(cur_line);
212+
// }
213+
// }
214+
// }
215+
// }
216+
155217
impl<'a, T: Borrow<str>> MultiLineText<'a, BackendCoord, T> {
156218
/// Compute the line layout
157219
pub fn compute_line_layout(&self) -> FontResult<Vec<LayoutBox>> {

0 commit comments

Comments
 (0)