-- @titre Approches des lettres témoins -- @title Sidebearings of the control letters -- @categorie relire -- @resume Les approches gauche et droite de H, O, n, o et du zéro dans chaque master, puis les glyphes dont une approche est très négative (souvent une erreur, sauf pour f, j et quelques italiques). -- @summary Left and right sidebearings of H, O, n, o and zero in every master, then the glyphs with a strongly negative sidebearing (often a mistake, except for f, j and some italics). -- Fontista · bibliothèque de scripts · https://fontista.thinkspark.dev/scripts.html local CONTROL = { "H", "O", "n", "o", "zero" } local NEGATIVE = 0.05 -- flag sidebearings below minus this share of the em (0.05 = -50 at 1000) local en = lang == "en" -- horizontal extent of the outline (curves sampled, components followed) local function extent(name, master, depth) local l = layer(name, master) if not l or l.ink or (depth or 0) > 5 then return nil end local x0, x1 = nil, nil local function add(x) if not x0 or x < x0 then x0 = x end if not x1 or x > x1 then x1 = x end end for _, c in ipairs(l.contours) do local n, first = #c.nodes, nil for i = 1, n do if c.nodes[i].kind ~= "off" then first = i break end end if first then local prev, offs = c.nodes[first], {} add(prev.x) local last = c.closed and n or (n - first) for k = 1, last do local q = c.nodes[(first - 1 + k) % n + 1] if q.kind == "off" then offs[#offs + 1] = q else for i = 1, (#offs == 0 and 1 or 24) do local t = i / (#offs == 0 and 1 or 24) local u = 1 - t local x = q.x if #offs == 1 then x = u * u * prev.x + 2 * u * t * offs[1].x + t * t * q.x elseif #offs >= 2 then x = u ^ 3 * prev.x + 3 * u * u * t * offs[1].x + 3 * u * t * t * offs[#offs].x + t ^ 3 * q.x end add(x) end prev, offs = q, {} end end end end for _, comp in ipairs(components(name, master)) do local a, b = extent(comp.base, master, (depth or 0) + 1) if a then add(a + comp.dx) add(b + comp.dx) end end return x0, x1, l.width end for _, m in ipairs(font.masters) do print("— " .. m.name) for _, g in ipairs(CONTROL) do local a, b, w = extent(g, m.id) if a then print(string.format(en and " %-6s left %5.0f right %5.0f width %5.0f" or " %-6s gauche %5.0f droite %5.0f chasse %5.0f", g, a, w - b, w)) end end local odd = {} for _, g in ipairs(font.glyphs) do local a, b, w = extent(g, m.id) if a and (a < -NEGATIVE * font.upm or w - b < -NEGATIVE * font.upm) then odd[#odd + 1] = string.format("%s (%.0f / %.0f)", g, a, w - b) end end if #odd > 0 then print(string.format(en and " strongly negative: %s" or " très négatives : %s", table.concat(odd, ", "))) end end