Skip to content

Commit 41281af

Browse files
committed
Ininital port of protrusion and expansion features to harf mode
1 parent 8ec8528 commit 41281af

4 files changed

Lines changed: 107 additions & 5 deletions

File tree

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
Change History
22
--------------
3+
2025-??-?? luaotfload v3.30
4+
* Support expansion and protrusion font features also in harf mode.
5+
36
2024-12-03 luaotfload v3.29
47

58
* Preserve subtypes while letterspacing.

ctan.ann

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,2 @@
1-
2024-12-03 luaotfload v3.29
2-
* Preserve subtypes while letterspacing.
3-
* Improve logging for auxiliary functions.
4-
* Improve cache path selection when parts of cache path are not writable.
5-
* Fix broken luaotfload-tool.
1+
2025-??-?? luaotfload v3.30
2+
* Support expansion and protrusion font features also in harf mode.

doc/luaotfload-main.tex

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@
6262
\endsection
6363

6464
\beginsection{Changes}
65+
\beginsubsection{New in version 3.30}
66+
\begin{itemize}
67+
\item Support expansion and protrusion font features also in harf mode.
68+
\end{itemize}
69+
\endsubsection
70+
6571
\beginsubsection{New in version 3.29}
6672
\begin{itemize}
6773
\item Preserve subtypes while letterspacing.

src/luaotfload-features.lua

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -941,6 +941,102 @@ fonts.constructors.features.otf.register {
941941
},
942942
}
943943

944+
-- Protrusion for HarfBuzz fonts, based on the `node` feature in fonts-ext
945+
local protrusion_setups = fonts.protrusions.setups
946+
947+
local function initializeprotrusion(tfmdata, value)
948+
local setup = protrusion_setups[value]
949+
if not setup then
950+
if value then
951+
texio.write_nl('term and log', string.format('unknown protrusion setup %q ignored', value))
952+
end
953+
return
954+
end
955+
local lookup = {}
956+
local name_to_index = tfmdata.resources.unicodes
957+
for k, v in next, setup do
958+
local ktype = type(k)
959+
if ktype == 'number' then
960+
lookup[k] = v
961+
elseif ktype == 'string' then
962+
local index = name_to_index[k]
963+
if index then
964+
lookup[index] = v
965+
end
966+
end
967+
end
968+
local quad = tfmdata.parameters.quad
969+
local factor = setup.factor or 1
970+
if quad ~= 0 then
971+
factor = factor * 1000/quad
972+
end
973+
local left = factor * (setup.left or 1)
974+
local right = factor * (setup.right or 1)
975+
for i, chr in next, tfmdata.characters do
976+
local width = chr.width or 0
977+
local v, pl, pr = lookup[i], nil, nil
978+
if v then
979+
pl, pr = v[1], v[2]
980+
end
981+
if pl and pl ~= 0 then chr.left_protruding = left * pl * width end
982+
if pr and pr ~= 0 then chr.right_protruding = right * pr * width end
983+
end
984+
end
985+
986+
fonts.constructors.features.otf.register {
987+
name = "protrusion",
988+
description = "shift characters into the left and or right margin",
989+
initializers = {
990+
plug = initializeprotrusion,
991+
}
992+
}
993+
994+
-- Expansion for HarfBuzz fonts, based on the `node` feature in fonts-ext
995+
local expansion_setups = fonts.expansions.setups
996+
997+
local function initializeexpansion(tfmdata, value)
998+
local setup = expansion_setups[value]
999+
if not setup then
1000+
if value then
1001+
texio.write_nl('term and log', string.format('unknown expansion setup %q ignored', value))
1002+
end
1003+
return
1004+
end
1005+
local lookup = {}
1006+
local name_to_index = tfmdata.resources.unicodes
1007+
for k, v in next, setup do
1008+
local ktype = type(k)
1009+
if ktype == 'number' then
1010+
lookup[k] = v
1011+
elseif ktype == 'string' then
1012+
local index = name_to_index[k]
1013+
if index then
1014+
lookup[index] = v
1015+
end
1016+
end
1017+
end
1018+
local factor = 1000 * (setup.factor or 1)
1019+
tfmdata.stretch = 10 * (setup.stretch or 0)
1020+
tfmdata.shrink = 10 * (setup.shrink or 0)
1021+
tfmdata.step = 10 * (setup.step or 0)
1022+
for i, chr in next, tfmdata.characters do
1023+
local v = lookup[i]
1024+
if v and v ~= 0 then
1025+
chr.expansion_factor = v * factor
1026+
elseif factor ~= 1000 then
1027+
chr.expansion_factor = factor
1028+
end
1029+
end
1030+
end
1031+
1032+
fonts.constructors.features.otf.register {
1033+
name = "expansion",
1034+
description = "apply hz optimization",
1035+
initializers = {
1036+
plug = initializeexpansion,
1037+
}
1038+
}
1039+
9441040
return function ()
9451041
if not fonts and fonts.handlers then
9461042
report ("log", 0, "features",

0 commit comments

Comments
 (0)