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,
0xec08...0xec0a,
0xec0d...0xec1e,
0xed00...0xf018,
0xf01a...0xf02f,
0xed00...0xf02f,
0xf031...0xf03c,
0xf03f,
0xf041...0xf043,
0xf045...0xf049,
0xf04b...0xf050,
@ -378,18 +378,16 @@ pub fn getConstraint(cp: u21) ?Constraint {
0xf07c...0xf080,
0xf082...0xf08b,
0xf08d...0xf091,
0xf093...0xf09e,
0xf0a0,
0xf093...0xf0a0,
0xf0a5...0xf0a9,
0xf0ab...0xf0c9,
0xf0cb...0xf0d5,
0xf0d7...0xf0dd,
0xf0df...0xf0e6,
0xf0e8...0xf295,
0xf297...0xf2c3,
0xf297...0xf2c4,
0xf2c6...0xf2ef,
0xf2f1...0xf305,
0xf307...0xf847,
0xf2f1...0xf847,
0xf0001...0xf1af0,
=> .{
.size = .fit_cover1,
@ -670,22 +668,15 @@ pub fn getConstraint(cp: u21) ?Constraint {
.relative_width = 0.8008342022940563,
.relative_x = 0.1991657977059437,
},
0xf019,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
},
0xf030,
0xf03e,
0xf071,
0xf08c,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.8751322751322751,
.relative_y = 0.0624338624338624,
},
@ -698,24 +689,13 @@ pub fn getConstraint(cp: u21) ?Constraint {
.relative_height = 0.7502645502645503,
.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,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8877888683953564,
.relative_height = 0.9992749363119733,
.relative_x = 0.0003164442515641,
.relative_y = 0.0001959631589261,
},
0xf044,
@ -724,37 +704,27 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9913442331878375,
.relative_height = 0.9923123057630445,
.relative_y = 0.0002010014265405,
},
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,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.5557122708039492,
.relative_height = 0.7506817256817256,
.relative_y = 0.1247354497354497,
},
0xf052,
0xf081,
0xf092,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8741409740917385,
.relative_height = 0.8748851565736010,
.relative_y = 0.0626172338785870,
},
@ -764,39 +734,26 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.4993711622401420,
.relative_height = 0.8759430588185509,
.relative_y = 0.0620882827561120,
},
0xf05a...0xf05b,
0xf0a2,
0xf0aa,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9987423244802840,
.relative_height = 0.9997176214776941,
.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,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8745600777856455,
.relative_height = 0.4993298596163721,
.relative_y = 0.1879786499051550,
},
@ -806,70 +763,25 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.8139763779527559,
.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,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.8885754583921015,
.relative_height = 0.9303101594008066,
.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,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9994081526966043,
.relative_height = 0.9998551487695376,
.relative_x = 0.0005918473033957,
},
0xf0a4,
=> .{
@ -877,7 +789,6 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9987423244802840,
.relative_height = 0.7500526916695081,
.relative_y = 0.1250334663306335,
},
@ -887,7 +798,6 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9675646540335450,
.relative_height = 0.8124689241215546,
.relative_y = 0.0938253501046103,
},
@ -906,9 +816,7 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7150686682199350,
.relative_height = 0.3756613756613756,
.relative_x = 0.0004030632809351,
.relative_y = 0.5708994708994709,
},
0xf0e7,
@ -917,9 +825,7 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7491243338952770,
.relative_height = 0.9998803756692248,
.relative_x = 0.0006021702214782,
.relative_y = 0.0001196243307751,
},
0xf296,
@ -928,28 +834,16 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9994800427141276,
.relative_height = 0.9627792014248586,
.relative_x = 0.0001795653226322,
.relative_y = 0.0187142907131644,
},
0xf2c4,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7523272214386461,
},
0xf2c5,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9883117728988424,
.relative_height = 0.8573155985489722,
.relative_x = 0.0004377219006858,
.relative_y = 0.0713422007255139,
},
0xf2f0,
@ -958,18 +852,9 @@ pub fn getConstraint(cp: u21) ?Constraint {
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.9987423244802840,
.relative_height = 0.9669226518842459,
.relative_y = 0.0165984862232646,
},
0xf306,
=> .{
.size = .fit_cover1,
.height = .icon,
.align_horizontal = .center1,
.align_vertical = .center1,
.relative_width = 0.7691584391161260,
},
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)}
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"]:
xMin = math.inf
yMin = math.inf
xMax = -math.inf
yMax = -math.inf
individual_bounds: dict[int, tuple[int, int, int, int]] = {}
individual_advances: set[float] = set()
for cp in group:
if cp not in cmap:
continue
glyph = glyphs[cmap[cp]]
individual_advances.add(glyph.width)
bounds = BoundsPen(glyphSet=glyphs)
glyph.draw(bounds)
individual_bounds[cp] = bounds.bounds
@ -302,16 +308,32 @@ def generate_zig_switch_arms(
yMax = max(bounds.bounds[3], yMax)
group_width = xMax - xMin
group_height = yMax - yMin
group_is_monospace = (len(individual_bounds) > 1) and (
len(individual_advances) == 1
)
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
this_bounds = individual_bounds[cp]
this_width = this_bounds[2] - this_bounds[0]
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_x"] = (this_bounds[0] - xMin) / group_width
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]