1#![cfg_attr(all(not(test), feature="clippy"), warn(result_unwrap_used))]
6#![cfg_attr(feature="clippy", warn(unseparated_literal_suffix))]
7#![cfg_attr(feature="clippy", warn(wrong_pub_self_convention))]
8
9#![cfg_attr(feature="clippy", feature(plugin))]
11#![cfg_attr(feature="clippy", plugin(clippy))]
12
13#![warn(missing_copy_implementations,
14 trivial_numeric_casts,
15 trivial_casts,
16 unused_extern_crates,
17 unused_import_braces,
18 unused_qualifications)]
19#![cfg_attr(feature="clippy", warn(cast_possible_truncation))]
20#![cfg_attr(feature="clippy", warn(cast_possible_wrap))]
21#![cfg_attr(feature="clippy", warn(cast_precision_loss))]
22#![cfg_attr(feature="clippy", warn(cast_sign_loss))]
23#![cfg_attr(feature="clippy", warn(missing_docs_in_private_items))]
24#![cfg_attr(feature="clippy", warn(mut_mut))]
25
26#![cfg_attr(feature="clippy", warn(print_stdout))]
29
30#![cfg_attr(all(not(test), feature="clippy"), warn(result_unwrap_used))]
34#![cfg_attr(feature="clippy", warn(unseparated_literal_suffix))]
35#![cfg_attr(feature="clippy", warn(wrong_pub_self_convention))]
36
37extern crate rusttype;
40extern crate euclid;
41
42pub mod types;
43pub mod cursor;
44pub mod glyph;
45pub mod line;
46
47use std::f32;
48use rusttype::Scale;
49use self::line::{LineRects, LineInfo, LineInfos};
50use self::types::*;
51
52
53
54pub type PositionedGlyph = rusttype::PositionedGlyph<'static>;
56
57pub type Font = rusttype::Font<'static>;
58
59pub use types::Align;
60
61#[derive(Copy, Clone, Debug, PartialEq)]
63pub enum Wrap {
64 NoWrap,
65 Character,
67 Whitespace,
69}
70
71pub fn get_text_size(text: &str,
72 font: &Font,
73 font_size: f32,
74 line_height: f32,
75 wrap: Wrap) -> Size {
76
77 let line_infos = LineInfos::new(text, font, font_size, wrap, f32::MAX);
78 let max_width = line_infos.fold(0.0, |max, line_info| f32::max(max, line_info.width));
79 Size::new(max_width, line_infos.count() as f32 * line_height)
80}
81
82pub fn get_text_height(text: &str,
83 font: &Font,
84 font_size: f32,
85 line_height: f32,
86 wrap: Wrap,
87 width: f32)
88 -> f32 {
89 let line_infos = LineInfos::new(text, font, font_size, wrap, width);
90 line_infos.count() as f32 * line_height
91}
92
93pub fn get_line_rects(text: &str,
94 rect: Rect,
95 font: &Font,
96 font_size: f32,
97 line_height: f32,
98 line_wrap: Wrap,
99 align: Align)
100 -> Vec<Rect> {
101
102 let line_infos: Vec<LineInfo> = LineInfos::new(text, font, font_size, line_wrap, rect.width())
103 .collect();
104 let line_infos = line_infos.iter().cloned();
105 let line_rects = LineRects::new(line_infos, font_size, rect, align, line_height);
106 line_rects.collect()
107}
108
109pub fn get_positioned_glyphs(text: &str,
110 rect: Rect,
111 font: &Font,
112 font_size: f32,
113 line_height: f32,
114 line_wrap: Wrap,
115 align: Align)
116 -> Vec<PositionedGlyph>
117{
118 let line_infos: Vec<LineInfo> = LineInfos::new(text, font, font_size, line_wrap, rect.width())
119 .collect();
120 let line_infos = line_infos.iter().cloned();
121 let line_texts = line_infos.clone().map(|info| &text[info.byte_range()]);
122 let line_rects = LineRects::new(line_infos, font_size, rect, align, line_height);
123 let scale = Scale::uniform(font_size);
124
125 let mut positioned_glyphs = Vec::new();
126 for (line_text, line_rect) in line_texts.zip(line_rects) {
127 let point = rusttype::Point {
129 x: line_rect.left(),
130 y: line_rect.top() + font_size,
131 };
132
133 positioned_glyphs.extend(font.glyphs_for(line_text.chars())
134 .scan((None, 0.0), |state, g| {
135 let &mut (last, x) = state;
136 let g = g.scaled(scale);
137
138 let kern = last.map(|last| font.pair_kerning(scale, last, g.id())).unwrap_or(0.0);
139 let width = g.h_metrics().advance_width;
140
141 let next = g.positioned(point + rusttype::vector(x, 0.0));
142 *state = (Some(next.id()), x + width + kern);
143 Some(next.standalone())
144 }));
145 }
146 positioned_glyphs
147}
148
149#[derive(Clone)]
152pub struct Lines<'a, I>
153 where I: Iterator<Item = std::ops::Range<usize>>
154{
155 text: &'a str,
156 ranges: I,
157}
158
159pub fn lines<I>(text: &str, ranges: I) -> Lines<I>
162 where I: Iterator<Item = std::ops::Range<usize>>
163{
164 Lines {
165 text: text,
166 ranges: ranges,
167 }
168}
169
170impl<'a, I> Iterator for Lines<'a, I>
171 where I: Iterator<Item = std::ops::Range<usize>>
172{
173 type Item = &'a str;
174 fn next(&mut self) -> Option<Self::Item> {
175 let Lines { text, ref mut ranges } = *self;
176 ranges.next().map(|range| &text[range])
177 }
178}
179
180pub fn pt_to_px(font_size_in_points: f32) -> f32 {
183 (font_size_in_points * 4.0) / 3.0
184}
185
186pub fn px_to_pt(font_size_in_px: f32) -> f32 {
187 (font_size_in_px * 3.0) / 4.0
188}
189
190pub fn pt_to_scale(font_size_in_points: f32) -> Scale {
192 Scale::uniform(font_size_in_points)
193}