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