1use std::mem;
7
8use crate::style;
9use crate::Context;
10use crate::Mm;
11
12pub struct Wrapper<'c, 's, I: Iterator<Item = style::StyledStr<'s>>> {
16 iter: I,
17 context: &'c Context,
18 width: Mm,
19 x: Mm,
20 buf: Vec<style::StyledCow<'s>>,
21}
22
23impl<'c, 's, I: Iterator<Item = style::StyledStr<'s>>> Wrapper<'c, 's, I> {
24 pub fn new(iter: I, context: &'c Context, width: Mm) -> Wrapper<'c, 's, I> {
26 Wrapper {
27 iter,
28 context,
29 width,
30 x: Mm(0.0),
31 buf: Vec::new(),
32 }
33 }
34}
35
36impl<'c, 's, I: Iterator<Item = style::StyledStr<'s>>> Iterator for Wrapper<'c, 's, I> {
37 type Item = (Vec<style::StyledCow<'s>>, usize);
40
41 fn next(&mut self) -> Option<(Vec<style::StyledCow<'s>>, usize)> {
42 while let Some(s) = self.iter.next() {
44 let mut width = s.width(&self.context.font_cache);
45
46 if self.x + width > self.width {
47 let mut delta = 0;
50 let s = if let Some((start, end)) = split(self.context, s, self.width - self.x) {
52 delta = start.s.len() + end.s.len() - s.s.len();
55 self.buf.push(start);
56 width = end.width(&self.context.font_cache);
57 end
58 } else {
59 s.into()
60 };
61
62 if width > self.width {
63 break;
67 }
68
69 let v = std::mem::take(&mut self.buf);
71 self.buf.push(s);
72 self.x = width;
73 return Some((v, delta));
74 } else {
75 self.buf.push(s.into());
77 self.x += width;
78 }
79 }
80
81 if self.buf.is_empty() {
82 None
83 } else {
84 Some((mem::take(&mut self.buf), 0))
85 }
86 }
87}
88
89#[cfg(not(feature = "hyphenation"))]
90fn split<'s>(
91 _context: &Context,
92 _s: style::StyledStr<'s>,
93 _len: Mm,
94) -> Option<(style::StyledCow<'s>, style::StyledCow<'s>)> {
95 None
96}
97
98#[cfg(feature = "hyphenation")]
101fn split<'s>(
102 context: &Context,
103 s: style::StyledStr<'s>,
104 width: Mm,
105) -> Option<(style::StyledCow<'s>, style::StyledCow<'s>)> {
106 use hyphenation::{Hyphenator, Iter};
107
108 let hyphenator = if let Some(hyphenator) = &context.hyphenator {
109 hyphenator
110 } else {
111 return None;
112 };
113
114 let mark = "-";
115 let mark_width = s.style.str_width(&context.font_cache, mark);
116
117 let hyphenated = hyphenator.hyphenate(s.s);
118 let segments: Vec<_> = hyphenated.iter().segments().collect();
119
120 let idx = segments
123 .iter()
124 .scan(Mm(0.0), |acc, t| {
125 *acc += s.style.str_width(&context.font_cache, t);
126 Some(*acc)
127 })
128 .position(|w| w + mark_width > width)
129 .unwrap_or_default();
130 if idx > 0 {
131 let idx = hyphenated.breaks[idx - 1];
132 let start = s.s[..idx].to_owned() + mark;
133 let end = &s.s[idx..];
134 Some((
135 style::StyledCow::new(start, s.style),
136 style::StyledCow::new(end, s.style),
137 ))
138 } else {
139 None
140 }
141}
142
143pub struct Words<I: Iterator<Item = style::StyledString>> {
145 iter: I,
146 s: Option<style::StyledString>,
147}
148
149impl<I: Iterator<Item = style::StyledString>> Words<I> {
150 pub fn new<IntoIter: IntoIterator<Item = style::StyledString, IntoIter = I>>(
152 iter: IntoIter,
153 ) -> Words<I> {
154 Words {
155 iter: iter.into_iter(),
156 s: None,
157 }
158 }
159}
160
161impl<I: Iterator<Item = style::StyledString>> Iterator for Words<I> {
162 type Item = style::StyledString;
163
164 fn next(&mut self) -> Option<style::StyledString> {
165 if self.s.as_ref().map(|s| s.s.is_empty()).unwrap_or(true) {
166 self.s = self.iter.next();
167 }
168
169 if let Some(s) = &mut self.s {
170 let n = s.s.find(' ').map(|i| i + 1).unwrap_or_else(|| s.s.len());
172 let mut tmp = s.s.split_off(n);
173 mem::swap(&mut tmp, &mut s.s);
174 Some(style::StyledString::new(tmp, s.style))
175 } else {
176 None
177 }
178 }
179}