Add font_patcher's grouped vs individual alignment

pull/8847/head
Daniel Wennberg 2025-09-06 16:57:42 -07:00 committed by Mitchell Hashimoto
parent 21aa70dc8b
commit a1b7ea2e71
2 changed files with 37 additions and 130 deletions

View File

@ -365,9 +365,9 @@ pub fn getConstraint(cp: u21) ?Constraint {
0xebd7...0xec06, 0xebd7...0xec06,
0xec08...0xec0a, 0xec08...0xec0a,
0xec0d...0xec1e, 0xec0d...0xec1e,
0xed00...0xf018, 0xed00...0xf02f,
0xf01a...0xf02f,
0xf031...0xf03c, 0xf031...0xf03c,
0xf03f,
0xf041...0xf043, 0xf041...0xf043,
0xf045...0xf049, 0xf045...0xf049,
0xf04b...0xf050, 0xf04b...0xf050,
@ -378,18 +378,16 @@ pub fn getConstraint(cp: u21) ?Constraint {
0xf07c...0xf080, 0xf07c...0xf080,
0xf082...0xf08b, 0xf082...0xf08b,
0xf08d...0xf091, 0xf08d...0xf091,
0xf093...0xf09e, 0xf093...0xf0a0,
0xf0a0,
0xf0a5...0xf0a9, 0xf0a5...0xf0a9,
0xf0ab...0xf0c9, 0xf0ab...0xf0c9,
0xf0cb...0xf0d5, 0xf0cb...0xf0d5,
0xf0d7...0xf0dd, 0xf0d7...0xf0dd,
0xf0df...0xf0e6, 0xf0df...0xf0e6,
0xf0e8...0xf295, 0xf0e8...0xf295,
0xf297...0xf2c3, 0xf297...0xf2c4,
0xf2c6...0xf2ef, 0xf2c6...0xf2ef,
0xf2f1...0xf305, 0xf2f1...0xf847,
0xf307...0xf847,
0xf0001...0xf1af0, 0xf0001...0xf1af0,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
@ -670,22 +668,15 @@ pub fn getConstraint(cp: u21) ?Constraint {
.relative_width = 0.8008342022940563, .relative_width = 0.8008342022940563,
.relative_x = 0.1991657977059437, .relative_x = 0.1991657977059437,
}, },
0xf019,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
},
0xf030, 0xf030,
0xf03e, 0xf03e,
0xf071,
0xf08c,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.8751322751322751, .relative_height = 0.8751322751322751,
.relative_y = 0.0624338624338624, .relative_y = 0.0624338624338624,
}, },
@ -698,24 +689,13 @@ pub fn getConstraint(cp: u21) ?Constraint {
.relative_height = 0.7502645502645503, .relative_height = 0.7502645502645503,
.relative_y = 0.1248677248677249, .relative_y = 0.1248677248677249,
}, },
0xf03f,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.5554597570408116,
.relative_x = 0.0005406676069582,
},
0xf040, 0xf040,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.8877888683953564,
.relative_height = 0.9992749363119733, .relative_height = 0.9992749363119733,
.relative_x = 0.0003164442515641,
.relative_y = 0.0001959631589261, .relative_y = 0.0001959631589261,
}, },
0xf044, 0xf044,
@ -724,37 +704,27 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9913442331878375,
.relative_height = 0.9923123057630445, .relative_height = 0.9923123057630445,
.relative_y = 0.0002010014265405, .relative_y = 0.0002010014265405,
}, },
0xf04a, 0xf04a,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.7506817256817256,
.relative_y = 0.1247354497354497,
},
0xf051, 0xf051,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.5557122708039492,
.relative_height = 0.7506817256817256, .relative_height = 0.7506817256817256,
.relative_y = 0.1247354497354497, .relative_y = 0.1247354497354497,
}, },
0xf052, 0xf052,
0xf081,
0xf092,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.8741409740917385,
.relative_height = 0.8748851565736010, .relative_height = 0.8748851565736010,
.relative_y = 0.0626172338785870, .relative_y = 0.0626172338785870,
}, },
@ -764,39 +734,26 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.4993711622401420,
.relative_height = 0.8759430588185509, .relative_height = 0.8759430588185509,
.relative_y = 0.0620882827561120, .relative_y = 0.0620882827561120,
}, },
0xf05a...0xf05b, 0xf05a...0xf05b,
0xf0a2,
0xf0aa, 0xf0aa,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9987423244802840,
.relative_height = 0.9997176214776941, .relative_height = 0.9997176214776941,
.relative_y = 0.0002010014265405, .relative_y = 0.0002010014265405,
}, },
0xf071,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.8751322751322751,
.relative_x = 0.0004701457451810,
.relative_y = 0.0624338624338624,
},
0xf078, 0xf078,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.8745600777856455,
.relative_height = 0.4993298596163721, .relative_height = 0.4993298596163721,
.relative_y = 0.1879786499051550, .relative_y = 0.1879786499051550,
}, },
@ -806,70 +763,25 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.8139763779527559, .relative_height = 0.8139763779527559,
.relative_y = 0.0930118110236220, .relative_y = 0.0930118110236220,
}, },
0xf081,
0xf092,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8740316426933279,
.relative_height = 0.8748851565736010,
.relative_y = 0.0626172338785870,
},
0xf08c,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7776210625293841,
.relative_height = 0.8751322751322751,
.relative_y = 0.0624338624338624,
},
0xf09f,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.5717654171704958,
.relative_x = 0.0006952841596131,
},
0xf0a1, 0xf0a1,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.9303101594008066, .relative_height = 0.9303101594008066,
.relative_y = 0.0349409448818898, .relative_y = 0.0349409448818898,
}, },
0xf0a2,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8749266777006549,
.relative_height = 0.9997176214776941,
.relative_x = 0.0001253913778381,
.relative_y = 0.0002010014265405,
},
0xf0a3, 0xf0a3,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9994081526966043,
.relative_height = 0.9998551487695376, .relative_height = 0.9998551487695376,
.relative_x = 0.0005918473033957,
}, },
0xf0a4, 0xf0a4,
=> .{ => .{
@ -877,7 +789,6 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9987423244802840,
.relative_height = 0.7500526916695081, .relative_height = 0.7500526916695081,
.relative_y = 0.1250334663306335, .relative_y = 0.1250334663306335,
}, },
@ -887,7 +798,6 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9675646540335450,
.relative_height = 0.8124689241215546, .relative_height = 0.8124689241215546,
.relative_y = 0.0938253501046103, .relative_y = 0.0938253501046103,
}, },
@ -906,9 +816,7 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.7150686682199350,
.relative_height = 0.3756613756613756, .relative_height = 0.3756613756613756,
.relative_x = 0.0004030632809351,
.relative_y = 0.5708994708994709, .relative_y = 0.5708994708994709,
}, },
0xf0e7, 0xf0e7,
@ -917,9 +825,7 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.7491243338952770,
.relative_height = 0.9998803756692248, .relative_height = 0.9998803756692248,
.relative_x = 0.0006021702214782,
.relative_y = 0.0001196243307751, .relative_y = 0.0001196243307751,
}, },
0xf296, 0xf296,
@ -928,28 +834,16 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9994800427141276,
.relative_height = 0.9627792014248586, .relative_height = 0.9627792014248586,
.relative_x = 0.0001795653226322,
.relative_y = 0.0187142907131644, .relative_y = 0.0187142907131644,
}, },
0xf2c4,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7523272214386461,
},
0xf2c5, 0xf2c5,
=> .{ => .{
.size = .fit_cover1, .size = .fit_cover1,
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9883117728988424,
.relative_height = 0.8573155985489722, .relative_height = 0.8573155985489722,
.relative_x = 0.0004377219006858,
.relative_y = 0.0713422007255139, .relative_y = 0.0713422007255139,
}, },
0xf2f0, 0xf2f0,
@ -958,18 +852,9 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon, .height = .icon,
.align_horizontal = .center1, .align_horizontal = .center1,
.align_vertical = .center1, .align_vertical = .center1,
.relative_width = 0.9987423244802840,
.relative_height = 0.9669226518842459, .relative_height = 0.9669226518842459,
.relative_y = 0.0165984862232646, .relative_y = 0.0165984862232646,
}, },
0xf306,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7691584391161260,
},
else => null, else => null,
}; };
} }

View File

@ -282,17 +282,23 @@ def generate_zig_switch_arms(
entries |= {k: v for k, v in attributes.items() if isinstance(k, int)} entries |= {k: v for k, v in attributes.items() if isinstance(k, int)}
if entry["ScaleRules"] is not None and "ScaleGroups" in entry["ScaleRules"]: if entry["ScaleRules"] is not None:
if "ScaleGroups" not in entry["ScaleRules"]:
raise ValueError(
f"Scale rule format {entry['ScaleRules']} not implemented."
)
for group in entry["ScaleRules"]["ScaleGroups"]: for group in entry["ScaleRules"]["ScaleGroups"]:
xMin = math.inf xMin = math.inf
yMin = math.inf yMin = math.inf
xMax = -math.inf xMax = -math.inf
yMax = -math.inf yMax = -math.inf
individual_bounds: dict[int, tuple[int, int, int, int]] = {} individual_bounds: dict[int, tuple[int, int, int, int]] = {}
individual_advances: set[float] = set()
for cp in group: for cp in group:
if cp not in cmap: if cp not in cmap:
continue continue
glyph = glyphs[cmap[cp]] glyph = glyphs[cmap[cp]]
individual_advances.add(glyph.width)
bounds = BoundsPen(glyphSet=glyphs) bounds = BoundsPen(glyphSet=glyphs)
glyph.draw(bounds) glyph.draw(bounds)
individual_bounds[cp] = bounds.bounds individual_bounds[cp] = bounds.bounds
@ -302,16 +308,32 @@ def generate_zig_switch_arms(
yMax = max(bounds.bounds[3], yMax) yMax = max(bounds.bounds[3], yMax)
group_width = xMax - xMin group_width = xMax - xMin
group_height = yMax - yMin group_height = yMax - yMin
group_is_monospace = (len(individual_bounds) > 1) and (
len(individual_advances) == 1
)
for cp in group: for cp in group:
if cp not in cmap or cp not in entries: if (
cp not in cmap
or cp not in entries
# Codepoints may contribute to the bounding box of multiple groups,
# but should be scaled according to the first group they are found
# in. Hence, to avoid overwriting, we need to skip codepoints that
# have already been assigned a scale group.
or "relative_height" in entries[cp]
):
continue continue
this_bounds = individual_bounds[cp] this_bounds = individual_bounds[cp]
this_width = this_bounds[2] - this_bounds[0]
this_height = this_bounds[3] - this_bounds[1] this_height = this_bounds[3] - this_bounds[1]
entries[cp]["relative_width"] = this_width / group_width
entries[cp]["relative_height"] = this_height / group_height entries[cp]["relative_height"] = this_height / group_height
entries[cp]["relative_x"] = (this_bounds[0] - xMin) / group_width
entries[cp]["relative_y"] = (this_bounds[1] - yMin) / group_height entries[cp]["relative_y"] = (this_bounds[1] - yMin) / group_height
# Horizontal alignment should only be grouped if the group is monospace,
# that is, if all glyphs in the group have the same advance width.
if group_is_monospace:
this_width = this_bounds[2] - this_bounds[0]
entries[cp]["relative_width"] = this_width / group_width
entries[cp]["relative_x"] = (
this_bounds[0] - xMin
) / group_width
del entries[0] del entries[0]