ariel-rs 0.1.0

A faithful Rust port of Mermaid JS — headless SVG diagram rendering without a browser
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
// Browser-measured Arial character widths.
// Generated by visual-regression/measure_chars.mjs — DO NOT EDIT MANUALLY.
// These are exact measurements from Chrome/Puppeteer using Arial font,
// matching the browser environment Mermaid renders in.

use std::collections::HashMap;

/// Returns the browser-measured pixel width of a single character at the given font size,
/// or `None` if the character is not in the measurement table.
/// Uses the full CHAR_WIDTHS table with linear interpolation between measured sizes.
pub fn browser_char_width(c: char, font_size: f64) -> Option<f64> {
    const SIZES: &[u32] = &[10, 12, 14, 16, 17, 18, 20, 24];

    // Find the two bracketing measured sizes
    let lower_size = SIZES
        .iter()
        .filter(|&&s| s as f64 <= font_size)
        .copied()
        .last();
    let upper_size = SIZES
        .iter()
        .filter(|&&s| s as f64 >= font_size)
        .copied()
        .next();

    match (lower_size, upper_size) {
        (Some(lo), Some(hi)) if lo == hi => CHAR_WIDTHS.get(&lo)?.get(&c).copied(),
        (Some(lo), Some(hi)) => {
            let w_lo = CHAR_WIDTHS.get(&lo)?.get(&c).copied()?;
            let w_hi = CHAR_WIDTHS.get(&hi)?.get(&c).copied()?;
            let t = (font_size - lo as f64) / (hi as f64 - lo as f64);
            Some(w_lo + t * (w_hi - w_lo))
        }
        (Some(lo), None) => CHAR_WIDTHS.get(&lo)?.get(&c).copied(),
        (None, Some(hi)) => CHAR_WIDTHS.get(&hi)?.get(&c).copied(),
        (None, None) => None,
    }
}

/// Returns the pixel width of a string at the given font size,
/// using browser-accurate Arial metrics.
pub fn measure_browser(text: &str, font_size: f64) -> (f64, f64) {
    let width: f64 = text
        .chars()
        .map(|c| browser_char_width(c, font_size).unwrap_or(font_size * 0.5))
        .sum();
    // Arial line height at the given font size (ascent + descent + line gap)
    // Empirically: ~1.162× font-size matches browser getBoundingClientRect height
    let height = font_size * 1.162;
    (width, height)
}

/// Character width ratios relative to font-size, measured in Chrome at 16px Arial.
/// ratio = pixel_width / font_size
#[allow(dead_code)]
static CHAR_RATIO_AT_16: std::sync::LazyLock<HashMap<char, f64>> = std::sync::LazyLock::new(|| {
    let mut m = HashMap::new();
    m.insert('\u{0030}', 0.55664063_f64);
    m.insert('\u{0031}', 0.55664063_f64);
    m.insert('\u{0032}', 0.55664063_f64);
    m.insert('\u{0033}', 0.55664063_f64);
    m.insert('\u{0034}', 0.55664063_f64);
    m.insert('\u{0035}', 0.55664063_f64);
    m.insert('\u{0036}', 0.55664063_f64);
    m.insert('\u{0037}', 0.55664063_f64);
    m.insert('\u{0038}', 0.55664063_f64);
    m.insert('\u{0039}', 0.55664063_f64);
    m.insert('\u{0020}', 0.00000000_f64);
    m.insert('\u{0021}', 0.27832031_f64);
    m.insert('\u{0022}', 0.35546875_f64);
    m.insert('\u{0023}', 0.55664063_f64);
    m.insert('\u{0024}', 0.55664063_f64);
    m.insert('\u{0025}', 0.88964844_f64);
    m.insert('\u{0026}', 0.66699219_f64);
    m.insert('\u{0027}', 0.19140625_f64);
    m.insert('\u{0028}', 0.33300781_f64);
    m.insert('\u{0029}', 0.33300781_f64);
    m.insert('\u{002a}', 0.38964844_f64);
    m.insert('\u{002b}', 0.58398438_f64);
    m.insert('\u{002c}', 0.27832031_f64);
    m.insert('\u{002d}', 0.33300781_f64);
    m.insert('\u{002e}', 0.27832031_f64);
    m.insert('\u{002f}', 0.27832031_f64);
    m.insert('\u{003a}', 0.27832031_f64);
    m.insert('\u{003b}', 0.27832031_f64);
    m.insert('\u{003c}', 0.58398438_f64);
    m.insert('\u{003d}', 0.58398438_f64);
    m.insert('\u{003e}', 0.58398438_f64);
    m.insert('\u{003f}', 0.55664063_f64);
    m.insert('\u{0040}', 1.01562500_f64);
    m.insert('\u{0041}', 0.66699219_f64);
    m.insert('\u{0042}', 0.66699219_f64);
    m.insert('\u{0043}', 0.72265625_f64);
    m.insert('\u{0044}', 0.72265625_f64);
    m.insert('\u{0045}', 0.66699219_f64);
    m.insert('\u{0046}', 0.61132813_f64);
    m.insert('\u{0047}', 0.77832031_f64);
    m.insert('\u{0048}', 0.72265625_f64);
    m.insert('\u{0049}', 0.27832031_f64);
    m.insert('\u{004a}', 0.50000000_f64);
    m.insert('\u{004b}', 0.66699219_f64);
    m.insert('\u{004c}', 0.55664063_f64);
    m.insert('\u{004d}', 0.83300781_f64);
    m.insert('\u{004e}', 0.72265625_f64);
    m.insert('\u{004f}', 0.77832031_f64);
    m.insert('\u{0050}', 0.66699219_f64);
    m.insert('\u{0051}', 0.77832031_f64);
    m.insert('\u{0052}', 0.72265625_f64);
    m.insert('\u{0053}', 0.66699219_f64);
    m.insert('\u{0054}', 0.61132813_f64);
    m.insert('\u{0055}', 0.72265625_f64);
    m.insert('\u{0056}', 0.66699219_f64);
    m.insert('\u{0057}', 0.94433594_f64);
    m.insert('\u{0058}', 0.66699219_f64);
    m.insert('\u{0059}', 0.66699219_f64);
    m.insert('\u{005a}', 0.61132813_f64);
    m.insert('\u{005b}', 0.27832031_f64);
    m.insert('\u{005c}', 0.27832031_f64);
    m.insert('\u{005d}', 0.27832031_f64);
    m.insert('\u{005e}', 0.46972656_f64);
    m.insert('\u{005f}', 0.55664063_f64);
    m.insert('\u{0060}', 0.33300781_f64);
    m.insert('\u{0061}', 0.55664063_f64);
    m.insert('\u{0062}', 0.55664063_f64);
    m.insert('\u{0063}', 0.50000000_f64);
    m.insert('\u{0064}', 0.55664063_f64);
    m.insert('\u{0065}', 0.55664063_f64);
    m.insert('\u{0066}', 0.27832031_f64);
    m.insert('\u{0067}', 0.55664063_f64);
    m.insert('\u{0068}', 0.55664063_f64);
    m.insert('\u{0069}', 0.22265625_f64);
    m.insert('\u{006a}', 0.22265625_f64);
    m.insert('\u{006b}', 0.50000000_f64);
    m.insert('\u{006c}', 0.22265625_f64);
    m.insert('\u{006d}', 0.83300781_f64);
    m.insert('\u{006e}', 0.55664063_f64);
    m.insert('\u{006f}', 0.55664063_f64);
    m.insert('\u{0070}', 0.55664063_f64);
    m.insert('\u{0071}', 0.55664063_f64);
    m.insert('\u{0072}', 0.33300781_f64);
    m.insert('\u{0073}', 0.50000000_f64);
    m.insert('\u{0074}', 0.27832031_f64);
    m.insert('\u{0075}', 0.55664063_f64);
    m.insert('\u{0076}', 0.50000000_f64);
    m.insert('\u{0077}', 0.72265625_f64);
    m.insert('\u{0078}', 0.50000000_f64);
    m.insert('\u{0079}', 0.50000000_f64);
    m.insert('\u{007a}', 0.50000000_f64);
    m.insert('\u{007b}', 0.33398438_f64);
    m.insert('\u{007c}', 0.25976563_f64);
    m.insert('\u{007d}', 0.33398438_f64);
    m.insert('\u{007e}', 0.58398438_f64);
    m.insert('\u{00ab}', 0.55664063_f64);
    m.insert('\u{00bb}', 0.55664063_f64);
    m.insert('\u{2014}', 1.00000000_f64);
    m.insert('\u{2013}', 0.55664063_f64);
    m.insert('\u{2026}', 1.00000000_f64);
    m
});

/// Full width table at multiple sizes for accurate interpolation.
/// Structure: font_size -> char -> width_in_pixels
pub static CHAR_WIDTHS: std::sync::LazyLock<HashMap<u32, HashMap<char, f64>>> =
    std::sync::LazyLock::new(|| {
        let mut sizes = HashMap::new();
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 5.56250000_f64);
            m.insert('\u{0031}', 5.56250000_f64);
            m.insert('\u{0032}', 5.56250000_f64);
            m.insert('\u{0033}', 5.56250000_f64);
            m.insert('\u{0034}', 5.56250000_f64);
            m.insert('\u{0035}', 5.56250000_f64);
            m.insert('\u{0036}', 5.56250000_f64);
            m.insert('\u{0037}', 5.56250000_f64);
            m.insert('\u{0038}', 5.56250000_f64);
            m.insert('\u{0039}', 5.56250000_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 2.78125000_f64);
            m.insert('\u{0022}', 3.56250000_f64);
            m.insert('\u{0023}', 5.56250000_f64);
            m.insert('\u{0024}', 5.56250000_f64);
            m.insert('\u{0025}', 8.90625000_f64);
            m.insert('\u{0026}', 6.67187500_f64);
            m.insert('\u{0027}', 1.92187500_f64);
            m.insert('\u{0028}', 3.34375000_f64);
            m.insert('\u{0029}', 3.34375000_f64);
            m.insert('\u{002a}', 3.90625000_f64);
            m.insert('\u{002b}', 5.84375000_f64);
            m.insert('\u{002c}', 2.78125000_f64);
            m.insert('\u{002d}', 3.34375000_f64);
            m.insert('\u{002e}', 2.78125000_f64);
            m.insert('\u{002f}', 2.78125000_f64);
            m.insert('\u{003a}', 2.78125000_f64);
            m.insert('\u{003b}', 2.78125000_f64);
            m.insert('\u{003c}', 5.84375000_f64);
            m.insert('\u{003d}', 5.84375000_f64);
            m.insert('\u{003e}', 5.84375000_f64);
            m.insert('\u{003f}', 5.56250000_f64);
            m.insert('\u{0040}', 10.15625000_f64);
            m.insert('\u{0041}', 6.67187500_f64);
            m.insert('\u{0042}', 6.67187500_f64);
            m.insert('\u{0043}', 7.23437500_f64);
            m.insert('\u{0044}', 7.23437500_f64);
            m.insert('\u{0045}', 6.67187500_f64);
            m.insert('\u{0046}', 6.10937500_f64);
            m.insert('\u{0047}', 7.78125000_f64);
            m.insert('\u{0048}', 7.23437500_f64);
            m.insert('\u{0049}', 2.78125000_f64);
            m.insert('\u{004a}', 5.00000000_f64);
            m.insert('\u{004b}', 6.67187500_f64);
            m.insert('\u{004c}', 5.56250000_f64);
            m.insert('\u{004d}', 8.34375000_f64);
            m.insert('\u{004e}', 7.23437500_f64);
            m.insert('\u{004f}', 7.78125000_f64);
            m.insert('\u{0050}', 6.67187500_f64);
            m.insert('\u{0051}', 7.78125000_f64);
            m.insert('\u{0052}', 7.23437500_f64);
            m.insert('\u{0053}', 6.67187500_f64);
            m.insert('\u{0054}', 6.10937500_f64);
            m.insert('\u{0055}', 7.23437500_f64);
            m.insert('\u{0056}', 6.67187500_f64);
            m.insert('\u{0057}', 9.45312500_f64);
            m.insert('\u{0058}', 6.67187500_f64);
            m.insert('\u{0059}', 6.67187500_f64);
            m.insert('\u{005a}', 6.10937500_f64);
            m.insert('\u{005b}', 2.78125000_f64);
            m.insert('\u{005c}', 2.78125000_f64);
            m.insert('\u{005d}', 2.78125000_f64);
            m.insert('\u{005e}', 4.70312500_f64);
            m.insert('\u{005f}', 5.56250000_f64);
            m.insert('\u{0060}', 3.34375000_f64);
            m.insert('\u{0061}', 5.56250000_f64);
            m.insert('\u{0062}', 5.56250000_f64);
            m.insert('\u{0063}', 5.00000000_f64);
            m.insert('\u{0064}', 5.56250000_f64);
            m.insert('\u{0065}', 5.56250000_f64);
            m.insert('\u{0066}', 2.78125000_f64);
            m.insert('\u{0067}', 5.56250000_f64);
            m.insert('\u{0068}', 5.56250000_f64);
            m.insert('\u{0069}', 2.23437500_f64);
            m.insert('\u{006a}', 2.23437500_f64);
            m.insert('\u{006b}', 5.00000000_f64);
            m.insert('\u{006c}', 2.23437500_f64);
            m.insert('\u{006d}', 8.34375000_f64);
            m.insert('\u{006e}', 5.56250000_f64);
            m.insert('\u{006f}', 5.56250000_f64);
            m.insert('\u{0070}', 5.56250000_f64);
            m.insert('\u{0071}', 5.56250000_f64);
            m.insert('\u{0072}', 3.34375000_f64);
            m.insert('\u{0073}', 5.00000000_f64);
            m.insert('\u{0074}', 2.78125000_f64);
            m.insert('\u{0075}', 5.56250000_f64);
            m.insert('\u{0076}', 5.00000000_f64);
            m.insert('\u{0077}', 7.23437500_f64);
            m.insert('\u{0078}', 5.00000000_f64);
            m.insert('\u{0079}', 5.00000000_f64);
            m.insert('\u{007a}', 5.00000000_f64);
            m.insert('\u{007b}', 3.34375000_f64);
            m.insert('\u{007c}', 2.60937500_f64);
            m.insert('\u{007d}', 3.34375000_f64);
            m.insert('\u{007e}', 5.84375000_f64);
            m.insert('\u{00ab}', 5.56250000_f64);
            m.insert('\u{00bb}', 5.56250000_f64);
            m.insert('\u{2014}', 10.00000000_f64);
            m.insert('\u{2013}', 5.56250000_f64);
            m.insert('\u{2026}', 10.00000000_f64);
            sizes.insert(10_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 6.68750000_f64);
            m.insert('\u{0031}', 6.68750000_f64);
            m.insert('\u{0032}', 6.68750000_f64);
            m.insert('\u{0033}', 6.68750000_f64);
            m.insert('\u{0034}', 6.68750000_f64);
            m.insert('\u{0035}', 6.68750000_f64);
            m.insert('\u{0036}', 6.68750000_f64);
            m.insert('\u{0037}', 6.68750000_f64);
            m.insert('\u{0038}', 6.68750000_f64);
            m.insert('\u{0039}', 6.68750000_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 3.34375000_f64);
            m.insert('\u{0022}', 4.26562500_f64);
            m.insert('\u{0023}', 6.68750000_f64);
            m.insert('\u{0024}', 6.68750000_f64);
            m.insert('\u{0025}', 10.67187500_f64);
            m.insert('\u{0026}', 8.01562500_f64);
            m.insert('\u{0027}', 2.29687500_f64);
            m.insert('\u{0028}', 4.00000000_f64);
            m.insert('\u{0029}', 4.00000000_f64);
            m.insert('\u{002a}', 4.67187500_f64);
            m.insert('\u{002b}', 7.01562500_f64);
            m.insert('\u{002c}', 3.34375000_f64);
            m.insert('\u{002d}', 4.00000000_f64);
            m.insert('\u{002e}', 3.34375000_f64);
            m.insert('\u{002f}', 3.34375000_f64);
            m.insert('\u{003a}', 3.34375000_f64);
            m.insert('\u{003b}', 3.34375000_f64);
            m.insert('\u{003c}', 7.01562500_f64);
            m.insert('\u{003d}', 7.01562500_f64);
            m.insert('\u{003e}', 7.01562500_f64);
            m.insert('\u{003f}', 6.68750000_f64);
            m.insert('\u{0040}', 12.18750000_f64);
            m.insert('\u{0041}', 8.01562500_f64);
            m.insert('\u{0042}', 8.01562500_f64);
            m.insert('\u{0043}', 8.67187500_f64);
            m.insert('\u{0044}', 8.67187500_f64);
            m.insert('\u{0045}', 8.01562500_f64);
            m.insert('\u{0046}', 7.34375000_f64);
            m.insert('\u{0047}', 9.34375000_f64);
            m.insert('\u{0048}', 8.67187500_f64);
            m.insert('\u{0049}', 3.34375000_f64);
            m.insert('\u{004a}', 6.00000000_f64);
            m.insert('\u{004b}', 8.01562500_f64);
            m.insert('\u{004c}', 6.68750000_f64);
            m.insert('\u{004d}', 10.00000000_f64);
            m.insert('\u{004e}', 8.67187500_f64);
            m.insert('\u{004f}', 9.34375000_f64);
            m.insert('\u{0050}', 8.01562500_f64);
            m.insert('\u{0051}', 9.34375000_f64);
            m.insert('\u{0052}', 8.67187500_f64);
            m.insert('\u{0053}', 8.01562500_f64);
            m.insert('\u{0054}', 7.34375000_f64);
            m.insert('\u{0055}', 8.67187500_f64);
            m.insert('\u{0056}', 8.01562500_f64);
            m.insert('\u{0057}', 11.32812500_f64);
            m.insert('\u{0058}', 8.01562500_f64);
            m.insert('\u{0059}', 8.01562500_f64);
            m.insert('\u{005a}', 7.34375000_f64);
            m.insert('\u{005b}', 3.34375000_f64);
            m.insert('\u{005c}', 3.34375000_f64);
            m.insert('\u{005d}', 3.34375000_f64);
            m.insert('\u{005e}', 5.64062500_f64);
            m.insert('\u{005f}', 6.68750000_f64);
            m.insert('\u{0060}', 4.00000000_f64);
            m.insert('\u{0061}', 6.68750000_f64);
            m.insert('\u{0062}', 6.68750000_f64);
            m.insert('\u{0063}', 6.00000000_f64);
            m.insert('\u{0064}', 6.68750000_f64);
            m.insert('\u{0065}', 6.68750000_f64);
            m.insert('\u{0066}', 3.34375000_f64);
            m.insert('\u{0067}', 6.68750000_f64);
            m.insert('\u{0068}', 6.68750000_f64);
            m.insert('\u{0069}', 2.67187500_f64);
            m.insert('\u{006a}', 2.67187500_f64);
            m.insert('\u{006b}', 6.00000000_f64);
            m.insert('\u{006c}', 2.67187500_f64);
            m.insert('\u{006d}', 10.00000000_f64);
            m.insert('\u{006e}', 6.68750000_f64);
            m.insert('\u{006f}', 6.68750000_f64);
            m.insert('\u{0070}', 6.68750000_f64);
            m.insert('\u{0071}', 6.68750000_f64);
            m.insert('\u{0072}', 4.00000000_f64);
            m.insert('\u{0073}', 6.00000000_f64);
            m.insert('\u{0074}', 3.34375000_f64);
            m.insert('\u{0075}', 6.68750000_f64);
            m.insert('\u{0076}', 6.00000000_f64);
            m.insert('\u{0077}', 8.67187500_f64);
            m.insert('\u{0078}', 6.00000000_f64);
            m.insert('\u{0079}', 6.00000000_f64);
            m.insert('\u{007a}', 6.00000000_f64);
            m.insert('\u{007b}', 4.01562500_f64);
            m.insert('\u{007c}', 3.12500000_f64);
            m.insert('\u{007d}', 4.01562500_f64);
            m.insert('\u{007e}', 7.01562500_f64);
            m.insert('\u{00ab}', 6.68750000_f64);
            m.insert('\u{00bb}', 6.68750000_f64);
            m.insert('\u{2014}', 12.00000000_f64);
            m.insert('\u{2013}', 6.68750000_f64);
            m.insert('\u{2026}', 12.00000000_f64);
            sizes.insert(12_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 7.79687500_f64);
            m.insert('\u{0031}', 7.79687500_f64);
            m.insert('\u{0032}', 7.79687500_f64);
            m.insert('\u{0033}', 7.79687500_f64);
            m.insert('\u{0034}', 7.79687500_f64);
            m.insert('\u{0035}', 7.79687500_f64);
            m.insert('\u{0036}', 7.79687500_f64);
            m.insert('\u{0037}', 7.79687500_f64);
            m.insert('\u{0038}', 7.79687500_f64);
            m.insert('\u{0039}', 7.79687500_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 3.89062500_f64);
            m.insert('\u{0022}', 4.98437500_f64);
            m.insert('\u{0023}', 7.79687500_f64);
            m.insert('\u{0024}', 7.79687500_f64);
            m.insert('\u{0025}', 12.45312500_f64);
            m.insert('\u{0026}', 9.34375000_f64);
            m.insert('\u{0027}', 2.68750000_f64);
            m.insert('\u{0028}', 4.67187500_f64);
            m.insert('\u{0029}', 4.67187500_f64);
            m.insert('\u{002a}', 5.45312500_f64);
            m.insert('\u{002b}', 8.18750000_f64);
            m.insert('\u{002c}', 3.89062500_f64);
            m.insert('\u{002d}', 4.67187500_f64);
            m.insert('\u{002e}', 3.89062500_f64);
            m.insert('\u{002f}', 3.89062500_f64);
            m.insert('\u{003a}', 3.89062500_f64);
            m.insert('\u{003b}', 3.89062500_f64);
            m.insert('\u{003c}', 8.18750000_f64);
            m.insert('\u{003d}', 8.18750000_f64);
            m.insert('\u{003e}', 8.18750000_f64);
            m.insert('\u{003f}', 7.79687500_f64);
            m.insert('\u{0040}', 14.21875000_f64);
            m.insert('\u{0041}', 9.34375000_f64);
            m.insert('\u{0042}', 9.34375000_f64);
            m.insert('\u{0043}', 10.12500000_f64);
            m.insert('\u{0044}', 10.12500000_f64);
            m.insert('\u{0045}', 9.34375000_f64);
            m.insert('\u{0046}', 8.56250000_f64);
            m.insert('\u{0047}', 10.89062500_f64);
            m.insert('\u{0048}', 10.12500000_f64);
            m.insert('\u{0049}', 3.89062500_f64);
            m.insert('\u{004a}', 7.00000000_f64);
            m.insert('\u{004b}', 9.34375000_f64);
            m.insert('\u{004c}', 7.79687500_f64);
            m.insert('\u{004d}', 11.67187500_f64);
            m.insert('\u{004e}', 10.12500000_f64);
            m.insert('\u{004f}', 10.89062500_f64);
            m.insert('\u{0050}', 9.34375000_f64);
            m.insert('\u{0051}', 10.89062500_f64);
            m.insert('\u{0052}', 10.12500000_f64);
            m.insert('\u{0053}', 9.34375000_f64);
            m.insert('\u{0054}', 8.56250000_f64);
            m.insert('\u{0055}', 10.12500000_f64);
            m.insert('\u{0056}', 9.34375000_f64);
            m.insert('\u{0057}', 13.21875000_f64);
            m.insert('\u{0058}', 9.34375000_f64);
            m.insert('\u{0059}', 9.34375000_f64);
            m.insert('\u{005a}', 8.56250000_f64);
            m.insert('\u{005b}', 3.89062500_f64);
            m.insert('\u{005c}', 3.89062500_f64);
            m.insert('\u{005d}', 3.89062500_f64);
            m.insert('\u{005e}', 6.57812500_f64);
            m.insert('\u{005f}', 7.79687500_f64);
            m.insert('\u{0060}', 4.67187500_f64);
            m.insert('\u{0061}', 7.79687500_f64);
            m.insert('\u{0062}', 7.79687500_f64);
            m.insert('\u{0063}', 7.00000000_f64);
            m.insert('\u{0064}', 7.79687500_f64);
            m.insert('\u{0065}', 7.79687500_f64);
            m.insert('\u{0066}', 3.89062500_f64);
            m.insert('\u{0067}', 7.79687500_f64);
            m.insert('\u{0068}', 7.79687500_f64);
            m.insert('\u{0069}', 3.12500000_f64);
            m.insert('\u{006a}', 3.12500000_f64);
            m.insert('\u{006b}', 7.00000000_f64);
            m.insert('\u{006c}', 3.12500000_f64);
            m.insert('\u{006d}', 11.67187500_f64);
            m.insert('\u{006e}', 7.79687500_f64);
            m.insert('\u{006f}', 7.79687500_f64);
            m.insert('\u{0070}', 7.79687500_f64);
            m.insert('\u{0071}', 7.79687500_f64);
            m.insert('\u{0072}', 4.67187500_f64);
            m.insert('\u{0073}', 7.00000000_f64);
            m.insert('\u{0074}', 3.89062500_f64);
            m.insert('\u{0075}', 7.79687500_f64);
            m.insert('\u{0076}', 7.00000000_f64);
            m.insert('\u{0077}', 10.12500000_f64);
            m.insert('\u{0078}', 7.00000000_f64);
            m.insert('\u{0079}', 7.00000000_f64);
            m.insert('\u{007a}', 7.00000000_f64);
            m.insert('\u{007b}', 4.68750000_f64);
            m.insert('\u{007c}', 3.64062500_f64);
            m.insert('\u{007d}', 4.68750000_f64);
            m.insert('\u{007e}', 8.18750000_f64);
            m.insert('\u{00ab}', 7.79687500_f64);
            m.insert('\u{00bb}', 7.79687500_f64);
            m.insert('\u{2014}', 14.00000000_f64);
            m.insert('\u{2013}', 7.79687500_f64);
            m.insert('\u{2026}', 14.00000000_f64);
            sizes.insert(14_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 8.90625000_f64);
            m.insert('\u{0031}', 8.90625000_f64);
            m.insert('\u{0032}', 8.90625000_f64);
            m.insert('\u{0033}', 8.90625000_f64);
            m.insert('\u{0034}', 8.90625000_f64);
            m.insert('\u{0035}', 8.90625000_f64);
            m.insert('\u{0036}', 8.90625000_f64);
            m.insert('\u{0037}', 8.90625000_f64);
            m.insert('\u{0038}', 8.90625000_f64);
            m.insert('\u{0039}', 8.90625000_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 4.45312500_f64);
            m.insert('\u{0022}', 5.68750000_f64);
            m.insert('\u{0023}', 8.90625000_f64);
            m.insert('\u{0024}', 8.90625000_f64);
            m.insert('\u{0025}', 14.23437500_f64);
            m.insert('\u{0026}', 10.67187500_f64);
            m.insert('\u{0027}', 3.06250000_f64);
            m.insert('\u{0028}', 5.32812500_f64);
            m.insert('\u{0029}', 5.32812500_f64);
            m.insert('\u{002a}', 6.23437500_f64);
            m.insert('\u{002b}', 9.34375000_f64);
            m.insert('\u{002c}', 4.45312500_f64);
            m.insert('\u{002d}', 5.32812500_f64);
            m.insert('\u{002e}', 4.45312500_f64);
            m.insert('\u{002f}', 4.45312500_f64);
            m.insert('\u{003a}', 4.45312500_f64);
            m.insert('\u{003b}', 4.45312500_f64);
            m.insert('\u{003c}', 9.34375000_f64);
            m.insert('\u{003d}', 9.34375000_f64);
            m.insert('\u{003e}', 9.34375000_f64);
            m.insert('\u{003f}', 8.90625000_f64);
            m.insert('\u{0040}', 16.25000000_f64);
            m.insert('\u{0041}', 10.67187500_f64);
            m.insert('\u{0042}', 10.67187500_f64);
            m.insert('\u{0043}', 11.56250000_f64);
            m.insert('\u{0044}', 11.56250000_f64);
            m.insert('\u{0045}', 10.67187500_f64);
            m.insert('\u{0046}', 9.78125000_f64);
            m.insert('\u{0047}', 12.45312500_f64);
            m.insert('\u{0048}', 11.56250000_f64);
            m.insert('\u{0049}', 4.45312500_f64);
            m.insert('\u{004a}', 8.00000000_f64);
            m.insert('\u{004b}', 10.67187500_f64);
            m.insert('\u{004c}', 8.90625000_f64);
            m.insert('\u{004d}', 13.32812500_f64);
            m.insert('\u{004e}', 11.56250000_f64);
            m.insert('\u{004f}', 12.45312500_f64);
            m.insert('\u{0050}', 10.67187500_f64);
            m.insert('\u{0051}', 12.45312500_f64);
            m.insert('\u{0052}', 11.56250000_f64);
            m.insert('\u{0053}', 10.67187500_f64);
            m.insert('\u{0054}', 9.78125000_f64);
            m.insert('\u{0055}', 11.56250000_f64);
            m.insert('\u{0056}', 10.67187500_f64);
            m.insert('\u{0057}', 15.10937500_f64);
            m.insert('\u{0058}', 10.67187500_f64);
            m.insert('\u{0059}', 10.67187500_f64);
            m.insert('\u{005a}', 9.78125000_f64);
            m.insert('\u{005b}', 4.45312500_f64);
            m.insert('\u{005c}', 4.45312500_f64);
            m.insert('\u{005d}', 4.45312500_f64);
            m.insert('\u{005e}', 7.51562500_f64);
            m.insert('\u{005f}', 8.90625000_f64);
            m.insert('\u{0060}', 5.32812500_f64);
            m.insert('\u{0061}', 8.90625000_f64);
            m.insert('\u{0062}', 8.90625000_f64);
            m.insert('\u{0063}', 8.00000000_f64);
            m.insert('\u{0064}', 8.90625000_f64);
            m.insert('\u{0065}', 8.90625000_f64);
            m.insert('\u{0066}', 4.45312500_f64);
            m.insert('\u{0067}', 8.90625000_f64);
            m.insert('\u{0068}', 8.90625000_f64);
            m.insert('\u{0069}', 3.56250000_f64);
            m.insert('\u{006a}', 3.56250000_f64);
            m.insert('\u{006b}', 8.00000000_f64);
            m.insert('\u{006c}', 3.56250000_f64);
            m.insert('\u{006d}', 13.32812500_f64);
            m.insert('\u{006e}', 8.90625000_f64);
            m.insert('\u{006f}', 8.90625000_f64);
            m.insert('\u{0070}', 8.90625000_f64);
            m.insert('\u{0071}', 8.90625000_f64);
            m.insert('\u{0072}', 5.32812500_f64);
            m.insert('\u{0073}', 8.00000000_f64);
            m.insert('\u{0074}', 4.45312500_f64);
            m.insert('\u{0075}', 8.90625000_f64);
            m.insert('\u{0076}', 8.00000000_f64);
            m.insert('\u{0077}', 11.56250000_f64);
            m.insert('\u{0078}', 8.00000000_f64);
            m.insert('\u{0079}', 8.00000000_f64);
            m.insert('\u{007a}', 8.00000000_f64);
            m.insert('\u{007b}', 5.34375000_f64);
            m.insert('\u{007c}', 4.15625000_f64);
            m.insert('\u{007d}', 5.34375000_f64);
            m.insert('\u{007e}', 9.34375000_f64);
            m.insert('\u{00ab}', 8.90625000_f64);
            m.insert('\u{00bb}', 8.90625000_f64);
            m.insert('\u{2014}', 16.00000000_f64);
            m.insert('\u{2013}', 8.90625000_f64);
            m.insert('\u{2026}', 16.00000000_f64);
            sizes.insert(16_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 9.46875000_f64);
            m.insert('\u{0031}', 9.46875000_f64);
            m.insert('\u{0032}', 9.46875000_f64);
            m.insert('\u{0033}', 9.46875000_f64);
            m.insert('\u{0034}', 9.46875000_f64);
            m.insert('\u{0035}', 9.46875000_f64);
            m.insert('\u{0036}', 9.46875000_f64);
            m.insert('\u{0037}', 9.46875000_f64);
            m.insert('\u{0038}', 9.46875000_f64);
            m.insert('\u{0039}', 9.46875000_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 4.73437500_f64);
            m.insert('\u{0022}', 6.04687500_f64);
            m.insert('\u{0023}', 9.46875000_f64);
            m.insert('\u{0024}', 9.46875000_f64);
            m.insert('\u{0025}', 15.12500000_f64);
            m.insert('\u{0026}', 11.34375000_f64);
            m.insert('\u{0027}', 3.25000000_f64);
            m.insert('\u{0028}', 5.67187500_f64);
            m.insert('\u{0029}', 5.67187500_f64);
            m.insert('\u{002a}', 6.62500000_f64);
            m.insert('\u{002b}', 9.93750000_f64);
            m.insert('\u{002c}', 4.73437500_f64);
            m.insert('\u{002d}', 5.67187500_f64);
            m.insert('\u{002e}', 4.73437500_f64);
            m.insert('\u{002f}', 4.73437500_f64);
            m.insert('\u{003a}', 4.73437500_f64);
            m.insert('\u{003b}', 4.73437500_f64);
            m.insert('\u{003c}', 9.93750000_f64);
            m.insert('\u{003d}', 9.93750000_f64);
            m.insert('\u{003e}', 9.93750000_f64);
            m.insert('\u{003f}', 9.46875000_f64);
            m.insert('\u{0040}', 17.26562500_f64);
            m.insert('\u{0041}', 11.34375000_f64);
            m.insert('\u{0042}', 11.34375000_f64);
            m.insert('\u{0043}', 12.28125000_f64);
            m.insert('\u{0044}', 12.28125000_f64);
            m.insert('\u{0045}', 11.34375000_f64);
            m.insert('\u{0046}', 10.39062500_f64);
            m.insert('\u{0047}', 13.23437500_f64);
            m.insert('\u{0048}', 12.28125000_f64);
            m.insert('\u{0049}', 4.73437500_f64);
            m.insert('\u{004a}', 8.50000000_f64);
            m.insert('\u{004b}', 11.34375000_f64);
            m.insert('\u{004c}', 9.46875000_f64);
            m.insert('\u{004d}', 14.17187500_f64);
            m.insert('\u{004e}', 12.28125000_f64);
            m.insert('\u{004f}', 13.23437500_f64);
            m.insert('\u{0050}', 11.34375000_f64);
            m.insert('\u{0051}', 13.23437500_f64);
            m.insert('\u{0052}', 12.28125000_f64);
            m.insert('\u{0053}', 11.34375000_f64);
            m.insert('\u{0054}', 10.39062500_f64);
            m.insert('\u{0055}', 12.28125000_f64);
            m.insert('\u{0056}', 11.34375000_f64);
            m.insert('\u{0057}', 16.04687500_f64);
            m.insert('\u{0058}', 11.34375000_f64);
            m.insert('\u{0059}', 11.34375000_f64);
            m.insert('\u{005a}', 10.39062500_f64);
            m.insert('\u{005b}', 4.73437500_f64);
            m.insert('\u{005c}', 4.73437500_f64);
            m.insert('\u{005d}', 4.73437500_f64);
            m.insert('\u{005e}', 7.98437500_f64);
            m.insert('\u{005f}', 9.46875000_f64);
            m.insert('\u{0060}', 5.67187500_f64);
            m.insert('\u{0061}', 9.46875000_f64);
            m.insert('\u{0062}', 9.46875000_f64);
            m.insert('\u{0063}', 8.50000000_f64);
            m.insert('\u{0064}', 9.46875000_f64);
            m.insert('\u{0065}', 9.46875000_f64);
            m.insert('\u{0066}', 4.73437500_f64);
            m.insert('\u{0067}', 9.46875000_f64);
            m.insert('\u{0068}', 9.46875000_f64);
            m.insert('\u{0069}', 3.78125000_f64);
            m.insert('\u{006a}', 3.78125000_f64);
            m.insert('\u{006b}', 8.50000000_f64);
            m.insert('\u{006c}', 3.78125000_f64);
            m.insert('\u{006d}', 14.17187500_f64);
            m.insert('\u{006e}', 9.46875000_f64);
            m.insert('\u{006f}', 9.46875000_f64);
            m.insert('\u{0070}', 9.46875000_f64);
            m.insert('\u{0071}', 9.46875000_f64);
            m.insert('\u{0072}', 5.67187500_f64);
            m.insert('\u{0073}', 8.50000000_f64);
            m.insert('\u{0074}', 4.73437500_f64);
            m.insert('\u{0075}', 9.46875000_f64);
            m.insert('\u{0076}', 8.50000000_f64);
            m.insert('\u{0077}', 12.28125000_f64);
            m.insert('\u{0078}', 8.50000000_f64);
            m.insert('\u{0079}', 8.50000000_f64);
            m.insert('\u{007a}', 8.50000000_f64);
            m.insert('\u{007b}', 5.68750000_f64);
            m.insert('\u{007c}', 4.42187500_f64);
            m.insert('\u{007d}', 5.68750000_f64);
            m.insert('\u{007e}', 9.93750000_f64);
            m.insert('\u{00ab}', 9.46875000_f64);
            m.insert('\u{00bb}', 9.46875000_f64);
            m.insert('\u{2014}', 17.00000000_f64);
            m.insert('\u{2013}', 9.46875000_f64);
            m.insert('\u{2026}', 17.00000000_f64);
            sizes.insert(17_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 10.01562500_f64);
            m.insert('\u{0031}', 10.01562500_f64);
            m.insert('\u{0032}', 10.01562500_f64);
            m.insert('\u{0033}', 10.01562500_f64);
            m.insert('\u{0034}', 10.01562500_f64);
            m.insert('\u{0035}', 10.01562500_f64);
            m.insert('\u{0036}', 10.01562500_f64);
            m.insert('\u{0037}', 10.01562500_f64);
            m.insert('\u{0038}', 10.01562500_f64);
            m.insert('\u{0039}', 10.01562500_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 5.01562500_f64);
            m.insert('\u{0022}', 6.39062500_f64);
            m.insert('\u{0023}', 10.01562500_f64);
            m.insert('\u{0024}', 10.01562500_f64);
            m.insert('\u{0025}', 16.01562500_f64);
            m.insert('\u{0026}', 12.01562500_f64);
            m.insert('\u{0027}', 3.43750000_f64);
            m.insert('\u{0028}', 6.00000000_f64);
            m.insert('\u{0029}', 6.00000000_f64);
            m.insert('\u{002a}', 7.01562500_f64);
            m.insert('\u{002b}', 10.51562500_f64);
            m.insert('\u{002c}', 5.01562500_f64);
            m.insert('\u{002d}', 6.00000000_f64);
            m.insert('\u{002e}', 5.01562500_f64);
            m.insert('\u{002f}', 5.01562500_f64);
            m.insert('\u{003a}', 5.01562500_f64);
            m.insert('\u{003b}', 5.01562500_f64);
            m.insert('\u{003c}', 10.51562500_f64);
            m.insert('\u{003d}', 10.51562500_f64);
            m.insert('\u{003e}', 10.51562500_f64);
            m.insert('\u{003f}', 10.01562500_f64);
            m.insert('\u{0040}', 18.28125000_f64);
            m.insert('\u{0041}', 12.01562500_f64);
            m.insert('\u{0042}', 12.01562500_f64);
            m.insert('\u{0043}', 13.00000000_f64);
            m.insert('\u{0044}', 13.00000000_f64);
            m.insert('\u{0045}', 12.01562500_f64);
            m.insert('\u{0046}', 11.00000000_f64);
            m.insert('\u{0047}', 14.01562500_f64);
            m.insert('\u{0048}', 13.00000000_f64);
            m.insert('\u{0049}', 5.01562500_f64);
            m.insert('\u{004a}', 9.00000000_f64);
            m.insert('\u{004b}', 12.01562500_f64);
            m.insert('\u{004c}', 10.01562500_f64);
            m.insert('\u{004d}', 15.00000000_f64);
            m.insert('\u{004e}', 13.00000000_f64);
            m.insert('\u{004f}', 14.01562500_f64);
            m.insert('\u{0050}', 12.01562500_f64);
            m.insert('\u{0051}', 14.01562500_f64);
            m.insert('\u{0052}', 13.00000000_f64);
            m.insert('\u{0053}', 12.01562500_f64);
            m.insert('\u{0054}', 11.00000000_f64);
            m.insert('\u{0055}', 13.00000000_f64);
            m.insert('\u{0056}', 12.01562500_f64);
            m.insert('\u{0057}', 17.00000000_f64);
            m.insert('\u{0058}', 12.01562500_f64);
            m.insert('\u{0059}', 12.01562500_f64);
            m.insert('\u{005a}', 11.00000000_f64);
            m.insert('\u{005b}', 5.01562500_f64);
            m.insert('\u{005c}', 5.01562500_f64);
            m.insert('\u{005d}', 5.01562500_f64);
            m.insert('\u{005e}', 8.45312500_f64);
            m.insert('\u{005f}', 10.01562500_f64);
            m.insert('\u{0060}', 6.00000000_f64);
            m.insert('\u{0061}', 10.01562500_f64);
            m.insert('\u{0062}', 10.01562500_f64);
            m.insert('\u{0063}', 9.00000000_f64);
            m.insert('\u{0064}', 10.01562500_f64);
            m.insert('\u{0065}', 10.01562500_f64);
            m.insert('\u{0066}', 5.01562500_f64);
            m.insert('\u{0067}', 10.01562500_f64);
            m.insert('\u{0068}', 10.01562500_f64);
            m.insert('\u{0069}', 4.00000000_f64);
            m.insert('\u{006a}', 4.00000000_f64);
            m.insert('\u{006b}', 9.00000000_f64);
            m.insert('\u{006c}', 4.00000000_f64);
            m.insert('\u{006d}', 15.00000000_f64);
            m.insert('\u{006e}', 10.01562500_f64);
            m.insert('\u{006f}', 10.01562500_f64);
            m.insert('\u{0070}', 10.01562500_f64);
            m.insert('\u{0071}', 10.01562500_f64);
            m.insert('\u{0072}', 6.00000000_f64);
            m.insert('\u{0073}', 9.00000000_f64);
            m.insert('\u{0074}', 5.01562500_f64);
            m.insert('\u{0075}', 10.01562500_f64);
            m.insert('\u{0076}', 9.00000000_f64);
            m.insert('\u{0077}', 13.00000000_f64);
            m.insert('\u{0078}', 9.00000000_f64);
            m.insert('\u{0079}', 9.00000000_f64);
            m.insert('\u{007a}', 9.00000000_f64);
            m.insert('\u{007b}', 6.01562500_f64);
            m.insert('\u{007c}', 4.68750000_f64);
            m.insert('\u{007d}', 6.01562500_f64);
            m.insert('\u{007e}', 10.51562500_f64);
            m.insert('\u{00ab}', 10.01562500_f64);
            m.insert('\u{00bb}', 10.01562500_f64);
            m.insert('\u{2014}', 18.00000000_f64);
            m.insert('\u{2013}', 10.01562500_f64);
            m.insert('\u{2026}', 18.00000000_f64);
            sizes.insert(18_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 11.12500000_f64);
            m.insert('\u{0031}', 11.12500000_f64);
            m.insert('\u{0032}', 11.12500000_f64);
            m.insert('\u{0033}', 11.12500000_f64);
            m.insert('\u{0034}', 11.12500000_f64);
            m.insert('\u{0035}', 11.12500000_f64);
            m.insert('\u{0036}', 11.12500000_f64);
            m.insert('\u{0037}', 11.12500000_f64);
            m.insert('\u{0038}', 11.12500000_f64);
            m.insert('\u{0039}', 11.12500000_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 5.56250000_f64);
            m.insert('\u{0022}', 7.10937500_f64);
            m.insert('\u{0023}', 11.12500000_f64);
            m.insert('\u{0024}', 11.12500000_f64);
            m.insert('\u{0025}', 17.79687500_f64);
            m.insert('\u{0026}', 13.34375000_f64);
            m.insert('\u{0027}', 3.82812500_f64);
            m.insert('\u{0028}', 6.67187500_f64);
            m.insert('\u{0029}', 6.67187500_f64);
            m.insert('\u{002a}', 7.79687500_f64);
            m.insert('\u{002b}', 11.68750000_f64);
            m.insert('\u{002c}', 5.56250000_f64);
            m.insert('\u{002d}', 6.67187500_f64);
            m.insert('\u{002e}', 5.56250000_f64);
            m.insert('\u{002f}', 5.56250000_f64);
            m.insert('\u{003a}', 5.56250000_f64);
            m.insert('\u{003b}', 5.56250000_f64);
            m.insert('\u{003c}', 11.68750000_f64);
            m.insert('\u{003d}', 11.68750000_f64);
            m.insert('\u{003e}', 11.68750000_f64);
            m.insert('\u{003f}', 11.12500000_f64);
            m.insert('\u{0040}', 20.31250000_f64);
            m.insert('\u{0041}', 13.34375000_f64);
            m.insert('\u{0042}', 13.34375000_f64);
            m.insert('\u{0043}', 14.45312500_f64);
            m.insert('\u{0044}', 14.45312500_f64);
            m.insert('\u{0045}', 13.34375000_f64);
            m.insert('\u{0046}', 12.21875000_f64);
            m.insert('\u{0047}', 15.56250000_f64);
            m.insert('\u{0048}', 14.45312500_f64);
            m.insert('\u{0049}', 5.56250000_f64);
            m.insert('\u{004a}', 10.00000000_f64);
            m.insert('\u{004b}', 13.34375000_f64);
            m.insert('\u{004c}', 11.12500000_f64);
            m.insert('\u{004d}', 16.67187500_f64);
            m.insert('\u{004e}', 14.45312500_f64);
            m.insert('\u{004f}', 15.56250000_f64);
            m.insert('\u{0050}', 13.34375000_f64);
            m.insert('\u{0051}', 15.56250000_f64);
            m.insert('\u{0052}', 14.45312500_f64);
            m.insert('\u{0053}', 13.34375000_f64);
            m.insert('\u{0054}', 12.21875000_f64);
            m.insert('\u{0055}', 14.45312500_f64);
            m.insert('\u{0056}', 13.34375000_f64);
            m.insert('\u{0057}', 18.89062500_f64);
            m.insert('\u{0058}', 13.34375000_f64);
            m.insert('\u{0059}', 13.34375000_f64);
            m.insert('\u{005a}', 12.21875000_f64);
            m.insert('\u{005b}', 5.56250000_f64);
            m.insert('\u{005c}', 5.56250000_f64);
            m.insert('\u{005d}', 5.56250000_f64);
            m.insert('\u{005e}', 9.39062500_f64);
            m.insert('\u{005f}', 11.12500000_f64);
            m.insert('\u{0060}', 6.67187500_f64);
            m.insert('\u{0061}', 11.12500000_f64);
            m.insert('\u{0062}', 11.12500000_f64);
            m.insert('\u{0063}', 10.00000000_f64);
            m.insert('\u{0064}', 11.12500000_f64);
            m.insert('\u{0065}', 11.12500000_f64);
            m.insert('\u{0066}', 5.56250000_f64);
            m.insert('\u{0067}', 11.12500000_f64);
            m.insert('\u{0068}', 11.12500000_f64);
            m.insert('\u{0069}', 4.45312500_f64);
            m.insert('\u{006a}', 4.45312500_f64);
            m.insert('\u{006b}', 10.00000000_f64);
            m.insert('\u{006c}', 4.45312500_f64);
            m.insert('\u{006d}', 16.67187500_f64);
            m.insert('\u{006e}', 11.12500000_f64);
            m.insert('\u{006f}', 11.12500000_f64);
            m.insert('\u{0070}', 11.12500000_f64);
            m.insert('\u{0071}', 11.12500000_f64);
            m.insert('\u{0072}', 6.67187500_f64);
            m.insert('\u{0073}', 10.00000000_f64);
            m.insert('\u{0074}', 5.56250000_f64);
            m.insert('\u{0075}', 11.12500000_f64);
            m.insert('\u{0076}', 10.00000000_f64);
            m.insert('\u{0077}', 14.45312500_f64);
            m.insert('\u{0078}', 10.00000000_f64);
            m.insert('\u{0079}', 10.00000000_f64);
            m.insert('\u{007a}', 10.00000000_f64);
            m.insert('\u{007b}', 6.68750000_f64);
            m.insert('\u{007c}', 5.20312500_f64);
            m.insert('\u{007d}', 6.68750000_f64);
            m.insert('\u{007e}', 11.68750000_f64);
            m.insert('\u{00ab}', 11.12500000_f64);
            m.insert('\u{00bb}', 11.12500000_f64);
            m.insert('\u{2014}', 20.00000000_f64);
            m.insert('\u{2013}', 11.12500000_f64);
            m.insert('\u{2026}', 20.00000000_f64);
            sizes.insert(20_u32, m);
        }
        {
            let mut m = HashMap::new();
            m.insert('\u{0030}', 13.35937500_f64);
            m.insert('\u{0031}', 13.35937500_f64);
            m.insert('\u{0032}', 13.35937500_f64);
            m.insert('\u{0033}', 13.35937500_f64);
            m.insert('\u{0034}', 13.35937500_f64);
            m.insert('\u{0035}', 13.35937500_f64);
            m.insert('\u{0036}', 13.35937500_f64);
            m.insert('\u{0037}', 13.35937500_f64);
            m.insert('\u{0038}', 13.35937500_f64);
            m.insert('\u{0039}', 13.35937500_f64);
            m.insert('\u{0020}', 0.00000000_f64);
            m.insert('\u{0021}', 6.67187500_f64);
            m.insert('\u{0022}', 8.53125000_f64);
            m.insert('\u{0023}', 13.35937500_f64);
            m.insert('\u{0024}', 13.35937500_f64);
            m.insert('\u{0025}', 21.34375000_f64);
            m.insert('\u{0026}', 16.01562500_f64);
            m.insert('\u{0027}', 4.59375000_f64);
            m.insert('\u{0028}', 8.00000000_f64);
            m.insert('\u{0029}', 8.00000000_f64);
            m.insert('\u{002a}', 9.34375000_f64);
            m.insert('\u{002b}', 14.01562500_f64);
            m.insert('\u{002c}', 6.67187500_f64);
            m.insert('\u{002d}', 8.00000000_f64);
            m.insert('\u{002e}', 6.67187500_f64);
            m.insert('\u{002f}', 6.67187500_f64);
            m.insert('\u{003a}', 6.67187500_f64);
            m.insert('\u{003b}', 6.67187500_f64);
            m.insert('\u{003c}', 14.01562500_f64);
            m.insert('\u{003d}', 14.01562500_f64);
            m.insert('\u{003e}', 14.01562500_f64);
            m.insert('\u{003f}', 13.35937500_f64);
            m.insert('\u{0040}', 24.37500000_f64);
            m.insert('\u{0041}', 16.01562500_f64);
            m.insert('\u{0042}', 16.01562500_f64);
            m.insert('\u{0043}', 17.34375000_f64);
            m.insert('\u{0044}', 17.34375000_f64);
            m.insert('\u{0045}', 16.01562500_f64);
            m.insert('\u{0046}', 14.67187500_f64);
            m.insert('\u{0047}', 18.67187500_f64);
            m.insert('\u{0048}', 17.34375000_f64);
            m.insert('\u{0049}', 6.67187500_f64);
            m.insert('\u{004a}', 12.00000000_f64);
            m.insert('\u{004b}', 16.01562500_f64);
            m.insert('\u{004c}', 13.35937500_f64);
            m.insert('\u{004d}', 20.00000000_f64);
            m.insert('\u{004e}', 17.34375000_f64);
            m.insert('\u{004f}', 18.67187500_f64);
            m.insert('\u{0050}', 16.01562500_f64);
            m.insert('\u{0051}', 18.67187500_f64);
            m.insert('\u{0052}', 17.34375000_f64);
            m.insert('\u{0053}', 16.01562500_f64);
            m.insert('\u{0054}', 14.67187500_f64);
            m.insert('\u{0055}', 17.34375000_f64);
            m.insert('\u{0056}', 16.01562500_f64);
            m.insert('\u{0057}', 22.65625000_f64);
            m.insert('\u{0058}', 16.01562500_f64);
            m.insert('\u{0059}', 16.01562500_f64);
            m.insert('\u{005a}', 14.67187500_f64);
            m.insert('\u{005b}', 6.67187500_f64);
            m.insert('\u{005c}', 6.67187500_f64);
            m.insert('\u{005d}', 6.67187500_f64);
            m.insert('\u{005e}', 11.26562500_f64);
            m.insert('\u{005f}', 13.35937500_f64);
            m.insert('\u{0060}', 8.00000000_f64);
            m.insert('\u{0061}', 13.35937500_f64);
            m.insert('\u{0062}', 13.35937500_f64);
            m.insert('\u{0063}', 12.00000000_f64);
            m.insert('\u{0064}', 13.35937500_f64);
            m.insert('\u{0065}', 13.35937500_f64);
            m.insert('\u{0066}', 6.67187500_f64);
            m.insert('\u{0067}', 13.35937500_f64);
            m.insert('\u{0068}', 13.35937500_f64);
            m.insert('\u{0069}', 5.34375000_f64);
            m.insert('\u{006a}', 5.34375000_f64);
            m.insert('\u{006b}', 12.00000000_f64);
            m.insert('\u{006c}', 5.34375000_f64);
            m.insert('\u{006d}', 20.00000000_f64);
            m.insert('\u{006e}', 13.35937500_f64);
            m.insert('\u{006f}', 13.35937500_f64);
            m.insert('\u{0070}', 13.35937500_f64);
            m.insert('\u{0071}', 13.35937500_f64);
            m.insert('\u{0072}', 8.00000000_f64);
            m.insert('\u{0073}', 12.00000000_f64);
            m.insert('\u{0074}', 6.67187500_f64);
            m.insert('\u{0075}', 13.35937500_f64);
            m.insert('\u{0076}', 12.00000000_f64);
            m.insert('\u{0077}', 17.34375000_f64);
            m.insert('\u{0078}', 12.00000000_f64);
            m.insert('\u{0079}', 12.00000000_f64);
            m.insert('\u{007a}', 12.00000000_f64);
            m.insert('\u{007b}', 8.01562500_f64);
            m.insert('\u{007c}', 6.23437500_f64);
            m.insert('\u{007d}', 8.01562500_f64);
            m.insert('\u{007e}', 14.01562500_f64);
            m.insert('\u{00ab}', 13.35937500_f64);
            m.insert('\u{00bb}', 13.35937500_f64);
            m.insert('\u{2014}', 24.00000000_f64);
            m.insert('\u{2013}', 13.35937500_f64);
            m.insert('\u{2026}', 24.00000000_f64);
            sizes.insert(24_u32, m);
        }
        sizes
    });

/// Measure text width using the full browser-accurate lookup table.
/// Interpolates between measured sizes for exact results at any font size.
pub fn measure_exact(text: &str, font_size: f64) -> (f64, f64) {
    // Find bracketing sizes
    let lower_size = [10u32, 12, 14, 16, 17, 18, 20, 24]
        .iter()
        .filter(|&&s| s as f64 <= font_size)
        .copied()
        .last()
        .unwrap_or(10);
    let upper_size = [10u32, 12, 14, 16, 17, 18, 20, 24]
        .iter()
        .filter(|&&s| s as f64 >= font_size)
        .copied()
        .next()
        .unwrap_or(24);

    let width = if lower_size == upper_size {
        text.chars()
            .map(|c| {
                CHAR_WIDTHS
                    .get(&lower_size)
                    .and_then(|m| m.get(&c))
                    .copied()
                    .unwrap_or(font_size * 0.5)
            })
            .sum()
    } else {
        let t = (font_size - lower_size as f64) / (upper_size as f64 - lower_size as f64);
        text.chars()
            .map(|c| {
                let w_lo = CHAR_WIDTHS
                    .get(&lower_size)
                    .and_then(|m| m.get(&c))
                    .copied()
                    .unwrap_or(font_size * 0.5);
                let w_hi = CHAR_WIDTHS
                    .get(&upper_size)
                    .and_then(|m| m.get(&c))
                    .copied()
                    .unwrap_or(font_size * 0.5);
                w_lo + t * (w_hi - w_lo)
            })
            .sum()
    };

    let height = font_size * 1.162;
    (width, height)
}