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
//! 括弧と中身の縦位置を数字で比べる
use suki::font::{self, Font};
use suki::layout::{Content, Placed};
use suki::node::Style;
use suki::{layout, parse};
fn main() {
let loaded = font::load(std::fs::read("font/latinmodern-math.otf").unwrap()).unwrap();
let units = font::units_per_em(&loaded);
println!("括弧の字形が送り幅のどこに墨を置いているか");
for character in ['(', ')', '[', '{'] {
let base = font::glyph_of(&loaded, character).unwrap();
let mut glyphs = vec![base];
if let Some(growth) = font::vertical_growth(&loaded, base) {
glyphs.extend(growth.variant.iter().take(4).map(|variant| variant.glyph));
}
for glyph in glyphs {
let drawn = font::outline_of(&loaded, glyph);
let (left, _, right, _) = suki::outline::bounds(&drawn);
let advance = font::advance(&loaded, glyph);
println!(
" {character} 字形 {glyph} 送り {advance:.3} 墨 {:.3}..{:.3} 左の余白 {:.3} 右の余白 {:.3}",
left / units,
right / units,
left / units,
advance - right / units
);
}
}
for source in [
r"\left( \frac{a}{b} \right)",
r"\begin{pmatrix} a & b \\ c & d \end{pmatrix}",
r"\begin{bmatrix} 12 & 3 \\ 4 & 56 \end{bmatrix}",
] {
let node = parse(source).unwrap();
let placed = layout::layout(&node, &loaded, 1.0, Style::Auto, true);
let Content::Group(row) = &placed.content else {continue};
let Content::Group(parts) = &row[0].layout.content else {continue};
println!("\n{source}");
println!(" 数式軸 {:.3}", font::constant(&loaded).axis_height);
for (index, part) in parts.iter().enumerate() {
let name = match index {
0 => "左括弧",
1 => "中身",
_ => "右括弧",
};
report(name, part, &loaded);
if index == 1 {
if let Content::Group(cells) = &part.layout.content {
for cell in cells.iter().take(4) {
let ink = leftmost(&cell.layout, &loaded);
println!(
" セル x {:.3} 幅 {:.3} 墨の左端 {:.3}",
part.x + cell.x,
cell.layout.width,
part.x + cell.x + ink
);
}
}
}
}
}
}
/// まとまりの中でいちばん左に墨が来る位置
fn leftmost(placed: &suki::layout::Layout, loaded: &Font) -> f64 {
match &placed.content {
Content::Glyph {glyph, size, ..} => font::bearing(loaded, *glyph).0 * size,
Content::Group(children) => children
.first()
.map_or(0.0, |child| child.x + leftmost(&child.layout, loaded)),
Content::Rule => 0.0,
}
}
fn report(name: &str, part: &Placed, loaded: &Font) {
let top = part.y - part.layout.height;
let bottom = part.y + part.layout.depth;
let middle = (top + bottom) / 2.0;
let ink = match &part.layout.content {
Content::Glyph {glyph, ..} => {
let (height, depth) = font::extent(loaded, *glyph);
format!(" 字形 {glyph} 墨 {:.3}..{:.3}", -height, depth)
}
_ => String::new(),
};
println!(
" {name} x {:.3} 幅 {:.3} 上 {top:.3} 下 {bottom:.3} 中央 {middle:.3}{ink}",
part.x, part.layout.width
);
}