Skip to content

Commit 4e16acf

Browse files
OmikhleiaDidier Willis
authored andcommitted
feat(core): Support ex-height and cap-height font adjustment
1 parent 2544c7d commit 4e16acf

1 file changed

Lines changed: 48 additions & 0 deletions

File tree

core/font.lua

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,58 @@ local icu = require("justenoughicu")
44

55
local lastshaper
66

7+
local bits = require("core.parserbits")
8+
local lpeg = require("lpeg")
9+
local Ct, Cg, P = lpeg.Ct, lpeg.Cg, lpeg.P
10+
local adjust_metric = P("ex-height") + P("cap-height")
11+
local adjustment = Ct(Cg(bits.number, "amount")^-1 * bits.ws * Cg(adjust_metric, "unit"))
12+
13+
local function measureFontAdjustment (metric)
14+
if metric == "ex-height" then
15+
-- Uses the height of lowercase letters.
16+
-- This is used to normalize lowercase letters across fonts.
17+
-- The height of the lowercase letter "x" is used as the reference.
18+
-- Another option would be to use the OS/2 font table sxHeight value when available.
19+
return SILE.shaper:measureChar("x").height
20+
end
21+
if metric == "cap-height" then
22+
-- Uses the the height of uppercase letters.
23+
-- This is used to normalize uppercase letters across fonts.
24+
-- The height of the uppercase letter "H" is used as the reference.
25+
-- Another option would be to use the OS/2 font table sCapHeight value when available.
26+
return SILE.shaper:measureChar("H").height
27+
end
28+
SU.error("Unknown font adjust metric " .. metric)
29+
end
30+
31+
local function adjustedFontSize(options)
32+
local adjust = options.adjust
33+
local parsed = adjustment:match(adjust)
34+
if not parsed then
35+
SU.error("Couldn't parse font adjust value " .. adjust)
36+
end
37+
local baseOpts = pl.tablex.copy(options) -- shallow copy
38+
baseOpts.adjust = nil -- cancel for target font size calculation
39+
local currentMeasure = measureFontAdjustment(parsed.unit)
40+
local ratio = parsed.amount or 1
41+
local newMeasure
42+
-- Apply the target font size to measure the new font
43+
SILE.call("font", baseOpts, function ()
44+
newMeasure = measureFontAdjustment(parsed.unit)
45+
end)
46+
return SILE.settings:get("font.size") * ratio * (currentMeasure / newMeasure)
47+
end
48+
749
SILE.registerCommand("font", function (options, content)
850
if SU.ast.hasContent(content) then
951
SILE.settings:pushState()
1052
end
53+
if options.adjust then
54+
if options.size then
55+
SU.error("Can't specify both 'size' and 'adjust' in a \\font command")
56+
end
57+
SILE.settings:set("font.size", adjustedFontSize(options))
58+
end
1159
if options.filename then
1260
SILE.settings:set("font.filename", options.filename)
1361
end

0 commit comments

Comments
 (0)