1use super::StandardFont;
11
12pub fn unicode_to_winansi(ch: char) -> Option<u8> {
18 let cp = ch as u32;
19 if (0x20..=0x7E).contains(&cp) || (0xA0..=0xFF).contains(&cp) {
21 return Some(cp as u8);
22 }
23 match cp {
25 0x20AC => Some(0x80), 0x201A => Some(0x82), 0x0192 => Some(0x83), 0x201E => Some(0x84), 0x2026 => Some(0x85), 0x2020 => Some(0x86), 0x2021 => Some(0x87), 0x02C6 => Some(0x88), 0x2030 => Some(0x89), 0x0160 => Some(0x8A), 0x2039 => Some(0x8B), 0x0152 => Some(0x8C), 0x017D => Some(0x8E), 0x2018 => Some(0x91), 0x2019 => Some(0x92), 0x201C => Some(0x93), 0x201D => Some(0x94), 0x2022 => Some(0x95), 0x2013 => Some(0x96), 0x2014 => Some(0x97), 0x02DC => Some(0x98), 0x2122 => Some(0x99), 0x0161 => Some(0x9A), 0x203A => Some(0x9B), 0x0153 => Some(0x9C), 0x017E => Some(0x9E), 0x0178 => Some(0x9F), _ => None,
53 }
54}
55
56pub struct StandardFontMetrics {
60 pub widths: &'static [u16; 224],
61 pub default_width: u16,
62}
63
64impl StandardFontMetrics {
65 pub fn char_width(&self, ch: char, font_size: f64) -> f64 {
67 let code = ch as u32;
68 let w = if (32..=255).contains(&code) {
69 let idx = (code - 32) as usize;
70 let w = self.widths[idx];
71 if w > 0 {
72 w
73 } else {
74 self.default_width
75 }
76 } else if let Some(winansi) = unicode_to_winansi(ch) {
77 if winansi >= 32 {
78 let idx = (winansi as u32 - 32) as usize;
79 let w = self.widths[idx];
80 if w > 0 {
81 w
82 } else {
83 self.default_width
84 }
85 } else {
86 self.default_width
87 }
88 } else {
89 self.default_width
90 };
91 (w as f64 / 1000.0) * font_size
92 }
93
94 pub fn measure_string(&self, text: &str, font_size: f64, letter_spacing: f64) -> f64 {
96 let mut width = 0.0;
97 for ch in text.chars() {
98 width += self.char_width(ch, font_size) + letter_spacing;
99 }
100 width
101 }
102}
103
104impl StandardFont {
105 pub fn metrics(&self) -> StandardFontMetrics {
107 match self {
108 Self::Helvetica => StandardFontMetrics {
109 widths: &HELVETICA_WIDTHS,
110 default_width: 278,
111 },
112 Self::HelveticaBold => StandardFontMetrics {
113 widths: &HELVETICA_BOLD_WIDTHS,
114 default_width: 278,
115 },
116 Self::HelveticaOblique => StandardFontMetrics {
117 widths: &HELVETICA_OBLIQUE_WIDTHS,
118 default_width: 278,
119 },
120 Self::HelveticaBoldOblique => StandardFontMetrics {
121 widths: &HELVETICA_BOLD_OBLIQUE_WIDTHS,
122 default_width: 278,
123 },
124 Self::TimesRoman => StandardFontMetrics {
125 widths: &TIMES_ROMAN_WIDTHS,
126 default_width: 250,
127 },
128 Self::TimesBold => StandardFontMetrics {
129 widths: &TIMES_BOLD_WIDTHS,
130 default_width: 250,
131 },
132 Self::TimesItalic => StandardFontMetrics {
133 widths: &TIMES_ITALIC_WIDTHS,
134 default_width: 250,
135 },
136 Self::TimesBoldItalic => StandardFontMetrics {
137 widths: &TIMES_BOLD_ITALIC_WIDTHS,
138 default_width: 250,
139 },
140 Self::Courier => StandardFontMetrics {
141 widths: &COURIER_WIDTHS,
142 default_width: 600,
143 },
144 Self::CourierBold => StandardFontMetrics {
145 widths: &COURIER_BOLD_WIDTHS,
146 default_width: 600,
147 },
148 Self::CourierOblique => StandardFontMetrics {
149 widths: &COURIER_OBLIQUE_WIDTHS,
150 default_width: 600,
151 },
152 Self::CourierBoldOblique => StandardFontMetrics {
153 widths: &COURIER_BOLD_OBLIQUE_WIDTHS,
154 default_width: 600,
155 },
156 Self::Symbol => StandardFontMetrics {
157 widths: &SYMBOL_WIDTHS,
158 default_width: 250,
159 },
160 Self::ZapfDingbats => StandardFontMetrics {
161 widths: &ZAPF_DINGBATS_WIDTHS,
162 default_width: 278,
163 },
164 }
165 }
166}
167
168static HELVETICA_WIDTHS: [u16; 224] = [
172 278, 278, 355, 556, 556, 889, 667, 222, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556,
174 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667,
175 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667,
176 667, 611, 278, 278, 278, 469, 556, 222, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500,
177 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584,
178 0, 556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, 0, 222, 222, 333,
181 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
182 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333,
184 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667,
185 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778,
186 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556,
187 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556,
188 500,
189];
190
191static HELVETICA_BOLD_WIDTHS: [u16; 224] = [
192 278, 333, 474, 556, 556, 889, 722, 278, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556,
194 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667,
195 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667,
196 667, 611, 333, 278, 333, 584, 556, 278, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556,
197 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584,
198 0, 556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, 0, 278, 278, 500,
201 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
202 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333,
204 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722,
205 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778,
206 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556,
207 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611,
208 556,
209];
210
211static HELVETICA_OBLIQUE_WIDTHS: [u16; 224] = [
213 278, 278, 355, 556, 556, 889, 667, 222, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556,
215 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667, 722, 722, 667,
216 611, 778, 722, 278, 500, 667, 556, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667,
217 667, 611, 278, 278, 278, 469, 556, 222, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500,
218 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584,
219 0, 556, 0, 222, 556, 333, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, 0, 222, 222, 333,
222 333, 350, 556, 1000, 333, 1000, 500, 333, 944, 0, 500, 667,
223 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333,
225 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611, 667, 667, 667, 667, 667, 667,
226 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778,
227 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556,
228 278, 278, 278, 278, 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556,
229 500,
230];
231
232static HELVETICA_BOLD_OBLIQUE_WIDTHS: [u16; 224] = [
234 278, 333, 474, 556, 556, 889, 722, 278, 333, 333, 389, 584, 278, 333, 278, 278, 556, 556, 556,
236 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611, 975, 722, 722, 722, 722, 667,
237 611, 778, 722, 278, 556, 722, 611, 833, 722, 778, 667, 778, 722, 667, 611, 722, 667, 944, 667,
238 667, 611, 333, 278, 333, 584, 556, 278, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556,
239 278, 889, 611, 611, 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584,
240 0, 556, 0, 278, 556, 500, 1000, 556, 556, 333, 1000, 667, 333, 1000, 0, 611, 0, 0, 278, 278, 500,
243 500, 350, 556, 1000, 333, 1000, 556, 333, 944, 0, 500, 667,
244 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333, 400, 584, 333,
246 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611, 722, 722, 722, 722, 722, 722,
247 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278, 722, 722, 778, 778, 778, 778, 778, 584, 778,
248 722, 722, 722, 722, 667, 667, 611, 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556,
249 278, 278, 278, 278, 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611,
250 556,
251];
252
253static TIMES_ROMAN_WIDTHS: [u16; 224] = [
256 250, 333, 408, 500, 500, 833, 778, 333, 333, 333, 500, 564, 250, 333, 250, 278, 500, 500, 500,
258 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444, 921, 722, 667, 667, 722, 611,
259 556, 722, 722, 333, 389, 722, 611, 889, 722, 722, 556, 722, 667, 556, 611, 722, 722, 944, 722,
260 722, 611, 333, 278, 333, 469, 500, 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500,
261 278, 778, 500, 500, 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541,
262 0, 500, 0, 333, 500, 444, 1000, 500, 500, 333, 1000, 556, 333, 889, 0, 611, 0, 0, 333, 333, 444,
265 444, 350, 500, 1000, 333, 980, 389, 333, 722, 0, 444, 722,
266 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333, 400, 564, 300,
268 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444, 722, 722, 722, 722, 722, 722,
269 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 722, 722, 722, 722, 722, 722, 564, 722,
270 722, 722, 722, 722, 722, 556, 500, 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444,
271 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500,
272 500,
273];
274
275static TIMES_BOLD_WIDTHS: [u16; 224] = [
276 250, 333, 555, 500, 500, 1000, 833, 333, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500,
278 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 930, 722, 667, 722, 722, 667,
279 611, 778, 778, 389, 500, 778, 667, 944, 722, 778, 611, 778, 722, 556, 667, 722, 722, 1000, 722,
280 722, 667, 333, 278, 333, 581, 500, 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556,
281 278, 833, 556, 500, 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520,
282 0, 500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 1000, 0, 667, 0, 0, 333, 333, 500,
285 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 444, 722,
286 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333, 400, 570, 300,
288 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500, 722, 722, 722, 722, 722, 722,
289 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 778, 778, 778, 778, 778, 570, 778,
290 722, 722, 722, 722, 722, 611, 556, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444,
291 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556,
292 500,
293];
294
295static TIMES_ITALIC_WIDTHS: [u16; 224] = [
296 250, 333, 420, 500, 500, 833, 778, 333, 333, 333, 500, 675, 250, 333, 250, 278, 500, 500, 500,
298 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500, 920, 611, 611, 667, 722, 611,
299 611, 722, 722, 333, 444, 667, 556, 833, 667, 722, 611, 722, 611, 500, 556, 722, 611, 833, 611,
300 556, 556, 389, 278, 389, 422, 500, 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444,
301 278, 722, 500, 500, 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541,
302 0, 500, 0, 333, 500, 556, 889, 500, 500, 333, 1000, 500, 333, 944, 0, 556, 0, 0, 333, 333, 556,
305 556, 350, 500, 889, 333, 980, 389, 333, 667, 0, 389, 556,
306 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333, 400, 675, 300,
308 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500, 611, 611, 611, 611, 611, 611,
309 889, 667, 611, 611, 611, 611, 333, 333, 333, 333, 722, 667, 722, 722, 722, 722, 722, 675, 722,
310 722, 722, 722, 722, 556, 611, 500, 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444,
311 278, 278, 278, 278, 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500,
312 444,
313];
314
315static TIMES_BOLD_ITALIC_WIDTHS: [u16; 224] = [
316 250, 389, 555, 500, 500, 833, 778, 333, 333, 333, 500, 570, 250, 333, 250, 278, 500, 500, 500,
318 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500, 832, 667, 667, 667, 722, 667,
319 667, 722, 778, 389, 500, 667, 611, 889, 722, 722, 611, 722, 667, 556, 611, 722, 667, 889, 667,
320 611, 611, 333, 278, 333, 570, 500, 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500,
321 278, 778, 556, 500, 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570,
322 0, 500, 0, 333, 500, 500, 1000, 500, 500, 333, 1000, 556, 333, 944, 0, 611, 0, 0, 333, 333, 500,
325 500, 350, 500, 1000, 333, 1000, 389, 333, 722, 0, 389, 611,
326 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 570, 333, 747, 333, 400, 570, 300,
328 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500, 667, 667, 667, 667, 667, 667,
329 944, 667, 667, 667, 667, 667, 389, 389, 389, 389, 722, 722, 722, 722, 722, 722, 722, 570, 722,
330 722, 722, 722, 722, 611, 611, 500, 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444,
331 278, 278, 278, 278, 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500,
332 444,
333];
334
335static COURIER_WIDTHS: [u16; 224] = [
338 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
339 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
340 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
341 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
342 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
343 0, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, 0, 600, 600, 600,
344 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600,
345 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
346 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
347 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
348 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
349 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
350];
351
352static COURIER_BOLD_WIDTHS: [u16; 224] = [
353 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
354 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
355 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
356 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
357 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
358 0, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, 0, 600, 600, 600,
359 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600,
360 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
361 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
362 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
363 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
364 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
365];
366
367static COURIER_OBLIQUE_WIDTHS: [u16; 224] = [
368 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
369 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
370 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
371 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
372 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
373 0, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, 0, 600, 600, 600,
374 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600,
375 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
376 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
377 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
378 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
379 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
380];
381
382static COURIER_BOLD_OBLIQUE_WIDTHS: [u16; 224] = [
383 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
384 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
385 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
386 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
387 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
388 0, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 0, 0, 600, 600, 600,
389 600, 600, 600, 600, 600, 600, 600, 600, 600, 0, 600, 600, 600, 600, 600, 600, 600, 600, 600,
390 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
391 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
392 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
393 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
394 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600, 600,
395];
396
397static SYMBOL_WIDTHS: [u16; 224] = [
400 250, 333, 713, 500, 549, 833, 778, 439, 333, 333, 500, 549, 250, 549, 250, 278, 500, 500, 500,
401 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444, 549, 722, 667, 722, 612, 611,
402 763, 603, 722, 333, 631, 722, 686, 889, 722, 722, 768, 741, 556, 592, 611, 690, 439, 768, 645,
403 795, 611, 333, 863, 333, 658, 500, 500, 631, 549, 549, 494, 439, 521, 411, 603, 329, 603, 549,
404 549, 576, 521, 549, 549, 521, 549, 603, 439, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549,
405 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
406 0, 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603, 400, 549,
407 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658, 823, 686, 795, 987,
408 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713, 768, 713, 790, 790, 890, 823, 549,
409 250, 713, 603, 603, 1042, 987, 603, 987, 603, 494, 329, 790, 790, 786, 713, 384, 384, 384, 384,
410 384, 384, 494, 494, 494, 494, 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494,
411 494, 494, 0,
412];
413
414static ZAPF_DINGBATS_WIDTHS: [u16; 224] = [
415 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933, 911, 945, 974,
416 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537, 577, 692, 786, 788, 788, 790,
417 793, 794, 816, 823, 789, 841, 823, 833, 816, 831, 923, 744, 723, 749, 790, 792, 695, 776, 768,
418 792, 759, 707, 708, 682, 701, 826, 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785,
419 791, 873, 761, 762, 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668,
420 0, 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0, 0, 0, 0, 0, 0,
421 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788,
422 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
423 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
424 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834, 873, 828, 924, 924, 917, 930,
425 931, 463, 883, 836, 836, 867, 867, 696, 696, 874, 0, 874, 760, 946, 771, 865, 771, 888, 967,
426 888, 831, 873, 927, 970, 918, 0,
427];
428
429#[cfg(test)]
430mod tests {
431 use super::*;
432
433 #[test]
434 fn test_helvetica_known_widths() {
435 let m = StandardFont::Helvetica.metrics();
436 assert_eq!(m.widths[0], 278); assert_eq!(m.widths[33], 667); assert_eq!(m.widths[77], 833); }
441
442 #[test]
443 fn test_helvetica_bold_wider() {
444 let regular = StandardFont::Helvetica.metrics();
445 let bold = StandardFont::HelveticaBold.metrics();
446 assert_eq!(bold.widths[33], 722);
448 assert!(bold.widths[33] > regular.widths[33]);
449 }
450
451 #[test]
452 fn test_courier_monospaced() {
453 let m = StandardFont::Courier.metrics();
454 for &w in m.widths.iter() {
456 if w > 0 {
457 assert_eq!(w, 600, "Courier should be monospaced");
458 }
459 }
460 }
461
462 #[test]
463 fn test_char_width_calculation() {
464 let m = StandardFont::Helvetica.metrics();
465 let w = m.char_width(' ', 12.0);
467 assert!((w - 3.336).abs() < 0.001);
468 }
469
470 #[test]
471 fn test_measure_string() {
472 let m = StandardFont::Helvetica.metrics();
473 let w = m.measure_string("A", 12.0, 0.0);
474 assert!((w - 8.004).abs() < 0.001); }
476
477 #[test]
478 fn test_char_width_em_dash_uses_winansi() {
479 let m = StandardFont::Helvetica.metrics();
480 let w = m.char_width('\u{2014}', 10.0);
483 assert!(
484 (w - 10.0).abs() < 0.001,
485 "em dash should be 1000/1000 * 10 = 10.0, got {}",
486 w
487 );
488 }
489
490 #[test]
491 fn test_char_width_en_dash_uses_winansi() {
492 let m = StandardFont::Helvetica.metrics();
493 let w = m.char_width('\u{2013}', 10.0);
496 assert!(
497 (w - 5.56).abs() < 0.001,
498 "en dash should be 556/1000 * 10 = 5.56, got {}",
499 w
500 );
501 }
502
503 #[test]
504 fn test_unicode_to_winansi_mappings() {
505 assert_eq!(unicode_to_winansi('\u{2014}'), Some(0x97)); assert_eq!(unicode_to_winansi('\u{2013}'), Some(0x96)); assert_eq!(unicode_to_winansi('\u{201C}'), Some(0x93)); assert_eq!(unicode_to_winansi('\u{2026}'), Some(0x85)); assert_eq!(unicode_to_winansi('A'), Some(0x41)); assert_eq!(unicode_to_winansi('\u{4E00}'), None); }
512
513 #[test]
514 fn test_latin_extended_character_widths() {
515 let m = StandardFont::Helvetica.metrics();
516 let a_width = m.widths[33]; assert_eq!(m.widths[0xC0 - 32], a_width, "Agrave should match A"); assert_eq!(m.widths[0xC1 - 32], a_width, "Aacute should match A"); assert_eq!(m.widths[0xC2 - 32], a_width, "Acircumflex should match A"); assert_eq!(m.widths[0xC3 - 32], a_width, "Atilde should match A"); assert_eq!(m.widths[0xC4 - 32], a_width, "Adieresis should match A"); assert_eq!(m.widths[0xC5 - 32], a_width, "Aring should match A"); let w_a_dieresis = m.char_width('Ä', 10.0);
527 let w_a = m.char_width('A', 10.0);
528 assert!(
529 (w_a_dieresis - w_a).abs() < 0.001,
530 "Ä width ({}) should equal A width ({})",
531 w_a_dieresis,
532 w_a
533 );
534
535 let w_a_ring = m.char_width('Å', 10.0);
536 assert!(
537 (w_a_ring - w_a).abs() < 0.001,
538 "Å width ({}) should equal A width ({})",
539 w_a_ring,
540 w_a
541 );
542
543 let o_width = m.widths[0x4F - 32]; assert_eq!(m.widths[0xD6 - 32], o_width, "Odieresis should match O");
546
547 assert_eq!(m.widths[0xC6 - 32], 1000, "AE should be 1000");
549
550 let test_str = "ÅÄÖÉÈÊÑÜÚÙû";
552 let mut prev_x = 0.0;
553 for (i, ch) in test_str.chars().enumerate() {
554 let w = m.char_width(ch, 12.0);
555 assert!(
556 w > 1.0,
557 "Character '{}' (U+{:04X}) has suspiciously small width: {}",
558 ch,
559 ch as u32,
560 w
561 );
562 if i > 0 {
563 assert!(
564 prev_x > 0.0,
565 "Previous character should have non-zero width"
566 );
567 }
568 prev_x += w;
569 }
570 assert!(
572 prev_x > 50.0,
573 "Total width of '{}' at 12pt should be >50pt, got {}",
574 test_str,
575 prev_x
576 );
577 }
578
579 #[test]
580 fn test_latin_extended_widths_all_fonts() {
581 let fonts = [
583 StandardFont::Helvetica,
584 StandardFont::HelveticaBold,
585 StandardFont::HelveticaOblique,
586 StandardFont::HelveticaBoldOblique,
587 StandardFont::TimesRoman,
588 StandardFont::TimesBold,
589 StandardFont::TimesItalic,
590 StandardFont::TimesBoldItalic,
591 ];
592
593 for font in &fonts {
594 let m = font.metrics();
595 let a_width = m.widths[0x41 - 32];
597 let a_dieresis_width = m.widths[0xC4 - 32];
598 assert_eq!(
599 a_dieresis_width, a_width,
600 "{:?}: Ä width ({}) != A width ({})",
601 font, a_dieresis_width, a_width
602 );
603
604 let a_ring_width = m.widths[0xC5 - 32];
606 assert_eq!(
607 a_ring_width, a_width,
608 "{:?}: Å width ({}) != A width ({})",
609 font, a_ring_width, a_width
610 );
611
612 let o_width = m.widths[0x6F - 32];
614 let o_dieresis_width = m.widths[0xF6 - 32];
615 assert_eq!(
616 o_dieresis_width, o_width,
617 "{:?}: ö width ({}) != o width ({})",
618 font, o_dieresis_width, o_width
619 );
620 }
621 }
622
623 #[test]
624 fn test_page_placeholder_width_difference() {
625 let m = StandardFont::Helvetica.metrics();
626 let literal = m.measure_string("{{pageNumber}}", 12.0, 0.0);
627 let substituted = m.measure_string("00", 12.0, 0.0);
628 assert!(
630 literal > substituted * 3.0,
631 "Literal placeholder ({}) is much wider than substituted ({})",
632 literal,
633 substituted
634 );
635 }
636}