1
2use rusttype;
6use super::Font;
7use rusttype::Scale;
8use types::{Range, Align, Rect, RectExt};
9use std;
10use rusttype::GlyphId;
11use std::str::CharIndices;
12use std::iter::Peekable;
13use super::Wrap;
14use super::glyph::SelectedGlyphRectsPerLine;
15
16#[derive(Copy, Clone, Debug, PartialEq)]
17enum BreakType {
18 Wrap {
20 len_bytes: usize,
23 },
24 Newline {
26 len_bytes: usize,
28 },
29 End,
30}
31#[derive(Copy, Clone, Debug, PartialEq)]
32pub struct Break {
33 byte: usize,
35 char: usize,
37 break_type: BreakType,
38}
39impl Break {
40 fn new(byte: usize, char: usize, break_type: BreakType) -> Self {
41 Break {
42 byte: byte,
43 char: char,
44 break_type: break_type,
45 }
46 }
47}
48
49#[derive(Copy, Clone, Debug, PartialEq)]
55pub struct LineInfo {
56 pub start_byte: usize,
58 pub start_char: usize,
60 pub end_break: Break,
64 pub width: f32,
66}
67
68impl LineInfo {
69 pub fn end_byte(&self) -> usize {
71 self.end_break.byte
72 }
73
74 pub fn end_char(&self) -> usize {
76 self.end_break.char
77 }
78
79 pub fn byte_range(self) -> std::ops::Range<usize> {
81 self.start_byte..self.end_byte()
82 }
83
84 pub fn char_range(self) -> std::ops::Range<usize> {
86 self.start_char..self.end_char()
87 }
88}
89
90#[derive(Copy, Clone)]
99pub struct LineInfos<'a> {
100 text: &'a str,
101 font: &'a Font,
102 font_size: f32,
103 max_width: f32,
104 line_wrap: Wrap,
105 start_byte: usize,
107 start_char: usize,
109 last_break: Option<Break>,
111}
112
113impl<'a> LineInfos<'a> {
114 pub fn new(text: &'a str,
115 font: &'a Font,
116 font_size: f32,
117 line_wrap: Wrap,
118 max_width: f32)
119 -> Self {
120 LineInfos {
121 text: text,
122 font: font,
123 font_size: font_size,
124 max_width: max_width,
125 line_wrap: line_wrap,
126 start_byte: 0,
127 start_char: 0,
128 last_break: None,
129 }
130 }
131}
132
133impl<'a> Iterator for LineInfos<'a> {
134 type Item = LineInfo;
135 fn next(&mut self) -> Option<Self::Item> {
136 let LineInfos { text,
137 font,
138 font_size,
139 max_width,
140 line_wrap,
141 ref mut start_byte,
142 ref mut start_char,
143 ref mut last_break } = *self;
144
145 let text_line = &text[*start_byte..];
146 let (next, width) = match line_wrap {
147 Wrap::NoWrap => next_break(text_line, font, font_size),
148 Wrap::Character => next_break_by_character(text_line, font, font_size, max_width),
149 Wrap::Whitespace => next_break_by_whitespace(text_line, font, font_size, max_width),
150 };
151 match next.break_type {
152 BreakType::Newline { len_bytes } |
153 BreakType::Wrap { len_bytes } => {
154 if next.byte == 0 && len_bytes == 0 {
155 None
156 } else {
157 let next_break = Break::new(*start_byte + next.byte,
158 *start_char + next.char,
159 next.break_type);
160 let info = LineInfo {
161 start_byte: *start_byte,
162 start_char: *start_char,
163 end_break: next_break,
164 width: width,
165 };
166 *start_byte = info.start_byte + next.byte + len_bytes;
167 *start_char = info.start_char + next.char + 1;
168 *last_break = Some(next_break);
169 Some(info)
170 }
171 }
172 BreakType::End => {
173 let char = next.char;
174 let empty_line = {
177 match *last_break {
178 Some(last_break_) => {
179 match last_break_.break_type {
180 BreakType::Newline { .. } => true,
181 _ => false,
182 }
183 }
184 None => true,
185 }
186 };
187 if *start_byte < text.len() || empty_line {
188 let total_bytes = text.len();
189 let total_chars = *start_char + char;
190 let end_break = Break::new(total_bytes, total_chars, BreakType::End);
191 let info = LineInfo {
192 start_byte: *start_byte,
193 start_char: *start_char,
194 end_break: end_break,
195 width: width,
196 };
197 *start_byte = total_bytes;
198 *start_char = total_chars;
199 *last_break = Some(end_break);
200 Some(info)
201 } else {
202 None
203 }
204 }
205 }
206 }
207}
208
209#[derive(Clone)]
211pub struct LineRects<I> {
212 infos: I,
213 align: Align,
214 line_height: f32,
215 next: Option<Rect>,
216}
217
218impl<I> LineRects<I>
219 where I: Iterator<Item = LineInfo> + ExactSizeIterator
220{
221 pub fn new(mut infos: I,
226 font_size: f32,
227 bounding_rect: Rect,
228 align: Align,
229 line_height: f32)
230 -> Self {
231 let num_lines = infos.len();
232 let first_rect = infos.next().map(|first_info| {
233 let bounding_x = bounding_rect.x_range();
234 let bounding_y = bounding_rect.y_range();
235 let range = Range::new(0.0, first_info.width);
237 let x = match align {
238 Align::Start => range.align_start_of(bounding_x),
239 Align::Middle => range.align_middle_of(bounding_x),
240 Align::End => range.align_end_of(bounding_x),
241 };
242
243 let total_text_height = num_lines as f32 * line_height;
245 let total_text_y_range = Range::new(0.0, total_text_height);
246 let total_text_y = total_text_y_range.align_start_of(bounding_y);
247 let range = Range::new(0.0, font_size);
248 let y = range.align_start_of(total_text_y);
249
250 Rect::from_ranges(x, y)
251 });
252
253 LineRects {
254 infos: infos,
255 next: first_rect,
256 align: align,
257 line_height: line_height,
258 }
259 }
260}
261
262impl<I> Iterator for LineRects<I>
263 where I: Iterator<Item = LineInfo>
264{
265 type Item = Rect;
266 fn next(&mut self) -> Option<Self::Item> {
267 let LineRects { ref mut next, ref mut infos, align, line_height } = *self;
268 next.map(|line_rect| {
269 *next = infos.next().map(|info| {
270 let y = Range::new(line_rect.bottom(), line_rect.bottom() + line_height);
271 let x = {
272 let range = Range::new(0.0, info.width);
273 match align {
274 Align::Start => range.align_start_of(line_rect.x_range()),
275 Align::Middle => range.align_middle_of(line_rect.x_range()),
276 Align::End => range.align_end_of(line_rect.x_range()),
277 }
278 };
279 Rect::from_ranges(x, y)
280 });
281
282 line_rect
283 })
284 }
285}
286
287pub struct SelectedLineRects<'a, I> {
293 selected_glyph_rects_per_line: SelectedGlyphRectsPerLine<'a, I>,
294}
295
296impl<'a, I> SelectedLineRects<'a, I>
297 where I: Iterator<Item = (&'a str, Rect)>
298{
299 pub fn new(lines_with_rects: I,
306 font: &'a Font,
307 font_size: f32,
308 start: super::cursor::Index,
309 end: super::cursor::Index)
310 -> SelectedLineRects<'a, I> {
311 SelectedLineRects {
312 selected_glyph_rects_per_line: SelectedGlyphRectsPerLine::new(lines_with_rects,
313 font,
314 font_size,
315 start,
316 end),
317 }
318 }
319}
320impl<'a, I> Iterator for SelectedLineRects<'a, I>
321 where I: Iterator<Item = (&'a str, Rect)>
322{
323 type Item = Rect;
324 fn next(&mut self) -> Option<Self::Item> {
325 while let Some(mut rects) = self.selected_glyph_rects_per_line.next() {
326 if let Some(first_rect) = rects.next() {
327 let total_selected_rect = rects.fold(first_rect, |mut total, next| {
328 total.size.width = next.width();
330 total
331 });
332 return Some(total_selected_rect);
333 }
334 }
335 None
336 }
337}
338
339fn advance_width(ch: char, font: &Font, scale: Scale, last_glyph: &mut Option<GlyphId>) -> f32 {
348 let g = font.glyph(ch).unwrap().scaled(scale);
349 let kern = last_glyph.map(|last| font.pair_kerning(scale, last, g.id()))
350 .unwrap_or(0.0);
351 let advance_width = g.h_metrics().advance_width;
352 *last_glyph = Some(g.id());
353 (kern + advance_width)
354}
355
356fn peek_next_char(char_indices: &mut Peekable<CharIndices>, next_char_expected: char) -> bool {
357 if let Some(&(_, next_char)) = char_indices.peek() {
358 next_char == next_char_expected
359 } else {
360 false
361 }
362}
363
364fn next_break(text: &str, font: &Font, font_size: f32) -> (Break, f32) {
367 let scale = super::pt_to_scale(font_size);
368 let mut width = 0.0;
369 let mut char_i = 0;
370 let mut char_indices = text.char_indices().peekable();
371 let mut last_glyph = None;
372 while let Some((byte_i, ch)) = char_indices.next() {
373 if ch == '\r' && peek_next_char(&mut char_indices, '\n') {
375 let break_ = Break::new(byte_i, char_i, BreakType::Newline { len_bytes: 2 });
376 return (break_, width);
377 } else if ch == '\n' {
378 let break_ = Break::new(byte_i, char_i, BreakType::Newline { len_bytes: 1 });
379 return (break_, width);
380 }
381
382 width += advance_width(ch, font, scale, &mut last_glyph);
384 char_i += 1;
385 }
386 let break_ = Break::new(text.len(), char_i, BreakType::End);
387 (break_, width)
388}
389fn next_break_by_character(text: &str,
395 font: &Font,
396 font_size: f32,
397 max_width: f32)
398 -> (Break, f32) {
399 let scale = super::pt_to_scale(font_size);
400 let mut width = 0.0;
401 let mut char_i = 0;
402 let mut char_indices = text.char_indices().peekable();
403 let mut last_glyph = None;
404 while let Some((byte_i, ch)) = char_indices.next() {
405 if ch == '\r' && peek_next_char(&mut char_indices, '\n') {
407 let break_ = Break::new(byte_i, char_i, BreakType::Newline { len_bytes: 2 });
408 return (break_, width);
409 } else if ch == '\n' {
410 let break_ = Break::new(byte_i, char_i, BreakType::Newline { len_bytes: 1 });
411 return (break_, width);
412 }
413
414 let new_width = width + advance_width(ch, font, scale, &mut last_glyph);
416
417 if new_width > max_width {
419 let break_ = Break::new(byte_i, char_i, BreakType::Wrap { len_bytes: 0 });
420 return (break_, width);
421 }
422
423 width = new_width;
424 char_i += 1;
425 }
426
427 let break_ = Break::new(text.len(), char_i, BreakType::End);
428 (break_, width)
429}
430
431fn next_break_by_whitespace(text: &str,
440 font: &Font,
441 font_size: f32,
442 max_width: f32)
443 -> (Break, f32) {
444 struct Last {
445 byte: usize,
446 char: usize,
447 width_before: f32,
448 }
449 let scale = super::pt_to_scale(font_size);
450 let mut last_whitespace_start = None;
451 let mut width = 0.0;
452 let mut char_i = 0;
453 let mut char_indices = text.char_indices().peekable();
454 let mut last_glyph = None;
455 while let Some((byte_i, ch)) = char_indices.next() {
456
457 if ch == '\r' && peek_next_char(&mut char_indices, '\n') {
459 let break_ = Break::new(byte_i, char_i, BreakType::Newline { len_bytes: 2 });
460 return (break_, width);
461 } else if ch == '\n' {
462 let break_ = Break::new(byte_i, char_i, BreakType::Newline { len_bytes: 1 });
463 return (break_, width);
464 }
465
466 let new_width = width + advance_width(ch, font, scale, &mut last_glyph);
468
469 if new_width > max_width {
471 match last_whitespace_start {
472 Some(Last { byte, char, width_before }) => {
473 let break_ = Break::new(byte, char, BreakType::Wrap { len_bytes: 1 });
474 return (break_, width_before);
475 }
476 None => {
477 let break_ = Break::new(byte_i, char_i, BreakType::Wrap { len_bytes: 0 });
478 return (break_, width);
479 }
480 }
481 }
482
483 if ch.is_whitespace() {
485 last_whitespace_start = Some(Last {
486 byte: byte_i,
487 char: char_i,
488 width_before: width,
489 });
490 }
491
492 width = new_width;
493 char_i += 1;
494 }
495
496 let break_ = Break::new(text.len(), char_i, BreakType::End);
497 (break_, width)
498}
499
500pub fn width(text: &str, font: &Font, font_size: f32) -> f32 {
502 let scale = Scale::uniform(font_size);
503 let point = rusttype::Point { x: 0.0, y: 0.0 };
504
505 let mut total_w = 0.0;
506 for g in font.layout(text, scale, point) {
507 match g.pixel_bounding_box() {
508 Some(bb) => total_w = bb.max.x as f32,
509 None => total_w += g.unpositioned().h_metrics().advance_width,
510 }
511 }
512
513 total_w
514}