limn_text_layout/
glyph.rs1use super::Font;
4use types::{Range, Rect, RectExt};
5use std;
6use rusttype;
7use rusttype::LayoutIter;
8use super::line::LineInfo;
9
10pub struct GlyphRects<'a, 'b> {
12 y: Range,
16 next_left: f32,
18 layout: LayoutIter<'a, 'b>,
20}
21
22
23impl<'a, 'b> Iterator for GlyphRects<'a, 'b> {
24 type Item = Rect;
25 fn next(&mut self) -> Option<Self::Item> {
26 let GlyphRects { ref mut next_left, ref mut layout, y } = *self;
27 layout.next().map(|g| {
28 let left = *next_left;
29 let right = g.pixel_bounding_box()
30 .map(|bb| bb.max.x as f32)
31 .unwrap_or_else(|| left + g.unpositioned().h_metrics().advance_width);
32 *next_left = right;
33 let x = Range::new(left, right);
34 Rect::from_ranges(x, y)
35 })
36 }
37}
38
39pub struct GlyphRectsPerLine<'a, I> {
42 lines_with_rects: I,
43 font: &'a Font,
44 font_size: f32,
45}
46
47impl<'a, I> GlyphRectsPerLine<'a, I>
48 where I: Iterator<Item = (&'a str, Rect)>
49{
50 pub fn new(lines_with_rects: I, font: &'a Font, font_size: f32) -> GlyphRectsPerLine<'a, I> {
56 GlyphRectsPerLine {
57 lines_with_rects: lines_with_rects,
58 font: font,
59 font_size: font_size,
60 }
61 }
62}
63impl<'a, I> Iterator for GlyphRectsPerLine<'a, I>
64 where I: Iterator<Item = (&'a str, Rect)>
65{
66 type Item = GlyphRects<'a, 'a>;
67 fn next(&mut self) -> Option<Self::Item> {
68 let GlyphRectsPerLine { ref mut lines_with_rects, font, font_size } = *self;
69 let scale = super::pt_to_scale(font_size);
70 lines_with_rects.next().map(|(line_text, line_rect)| {
71 let (x, y) = (line_rect.left(), line_rect.top());
72 let point = rusttype::Point { x: x, y: y };
73 GlyphRects {
74 next_left: line_rect.left(),
75 layout: font.layout(line_text, scale, point),
76 y: line_rect.y_range(),
77 }
78 })
79 }
80}
81
82pub struct SelectedGlyphRects<'a, 'b> {
86 enumerated_rects: std::iter::Enumerate<GlyphRects<'a, 'b>>,
87 end_char_idx: usize,
88}
89impl<'a, 'b> Iterator for SelectedGlyphRects<'a, 'b> {
90 type Item = Rect;
91 fn next(&mut self) -> Option<Self::Item> {
92 let SelectedGlyphRects { ref mut enumerated_rects, end_char_idx } = *self;
93 enumerated_rects.next()
94 .and_then(|(i, rect)| if i < end_char_idx { Some(rect) } else { None })
95 }
96}
97
98
99pub struct SelectedGlyphRectsPerLine<'a, I> {
107 enumerated_rects_per_line: std::iter::Enumerate<GlyphRectsPerLine<'a, I>>,
108 start_cursor_idx: super::cursor::Index,
109 end_cursor_idx: super::cursor::Index,
110}
111
112impl<'a, I> SelectedGlyphRectsPerLine<'a, I>
113 where I: Iterator<Item = (&'a str, Rect)>
114{
115 pub fn new(lines_with_rects: I,
123 font: &'a Font,
124 font_size: f32,
125 start: super::cursor::Index,
126 end: super::cursor::Index)
127 -> SelectedGlyphRectsPerLine<'a, I> {
128 SelectedGlyphRectsPerLine {
129 enumerated_rects_per_line: GlyphRectsPerLine::new(lines_with_rects, font, font_size)
130 .enumerate(),
131 start_cursor_idx: start,
132 end_cursor_idx: end,
133 }
134 }
135}
136impl<'a, I> Iterator for SelectedGlyphRectsPerLine<'a, I>
137 where I: Iterator<Item = (&'a str, Rect)>
138{
139 type Item = SelectedGlyphRects<'a, 'a>;
140 fn next(&mut self) -> Option<Self::Item> {
141 let SelectedGlyphRectsPerLine { ref mut enumerated_rects_per_line,
142 start_cursor_idx,
143 end_cursor_idx } = *self;
144
145 enumerated_rects_per_line.next().map(|(i, rects)| {
146 let end_char_idx =
147 if i == end_cursor_idx.line {
149 end_cursor_idx.char
150 } else if start_cursor_idx.line <= i && i < end_cursor_idx.line {
152 std::u32::MAX as usize
153 } else {
155 0
156 };
157
158 let mut enumerated_rects = rects.enumerate();
159
160 if i == start_cursor_idx.line {
162 for _ in 0..start_cursor_idx.char {
163 enumerated_rects.next();
164 }
165 }
166
167 SelectedGlyphRects {
168 enumerated_rects: enumerated_rects,
169 end_char_idx: end_char_idx,
170 }
171 })
172 }
173}
174
175
176pub fn index_after_cursor<I>(mut line_infos: I, cursor_idx: super::cursor::Index) -> Option<usize>
181 where I: Iterator<Item = LineInfo>
182{
183 line_infos.nth(cursor_idx.line)
184 .and_then(|line_info| {
185 let start_char = line_info.start_char;
186 let end_char = line_info.end_char();
187 let char_index = start_char + cursor_idx.char;
188 if char_index <= end_char {
189 Some(char_index)
190 } else {
191 None
192 }
193 })
194}