font-imp-scripts.lmt /size: 6588 b    last modification: 2024-01-16 10:22
1if not modules then modules = { } end modules ['font-imp-scripts'] = {
2    version   = 1.001,
3    comment   = "companion to font-ini.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local getrange           = characters.getrange
10
11local settings_to_hash   = utilities.parsers.settings_to_hash
12
13if not context then return end
14
15-- the defaults are not yet ok
16
17local next, type, tonumber = next, type, tonumber
18local gmatch = string.gmatch
19local max = math.max
20
21local fonts              = fonts
22local utilities          = utilities
23
24local helpers            = fonts.helpers
25local charcommand        = helpers.commands.char
26local downcommand        = helpers.commands.down
27local upcommand          = helpers.commands.up
28
29local handlers           = fonts.handlers
30local otf                = handlers.otf
31local afm                = handlers.afm
32local registerotffeature = otf.features.register
33local registerafmfeature = afm.features.register
34
35local settings_to_hash   = utilities.parsers.settings_to_hash
36local sortedhash         = table.sortedhash
37
38local handlers           = fonts.handlers
39
40local sup                = nil
41local sub                = nil
42
43local function initialize(tfmdata,key,value)
44    --
45    if not sup then
46        sup = { }
47        sub = { }
48        for unicode, data in next, characters.data do
49            local specials = data.specials
50            if specials then
51                local what = specials[1]
52                if what == "super" then
53                    sup[unicode] = specials[2]
54                elseif what == "sub" then
55                    sub[unicode] = specials[2]
56                end
57            end
58        end
59    end
60    --
61    local spec
62    if value == true then
63        spec = { factor = 3/5, up = 5/4, down = 1/4 }
64    elseif type(value) == "number" then
65        spec = { factor = value, up = 5/4, down = 1/4 }
66    else
67        spec = settings_to_hash(value)
68    end
69    local factor = tonumber(spec.factor) or 3/5
70    local up     = tonumber(spec.up)     or 5/4
71    local down   = tonumber(spec.down)   or 1/4
72    --
73    local characters = tfmdata.characters
74    local parameters = tfmdata.parameters
75    local up         =  parameters.xheight * up
76    local down       = -parameters.xheight * down
77    -- disable sups/subs
78    local function add(unicode,other,go_up)
79        local old = characters[other]
80        if old then
81            local shift  = go_up and up or down
82            local width  = (old.width or 0) * factor
83            local height = (old.height or 0) * factor + shift
84            local depth  = go_up and 0 or max((old.depth  or 0) * factor + down,0)
85            characters[unicode] = {
86                width    = width,
87                height   = height,
88                depth    = depth,
89                commands = { { "offset", 0, shift, other, factor, factor } },
90             -- yoffset  = shift,
91             -- xscale   = factor,
92             -- yscale   = factor,
93             -- commands = { { "slot", 0, other } }, -- { slotcommand[0][other] or charcommand[other] }
94            }
95        end
96    end
97    for unicode, other in sortedhash(sup) do
98        add(unicode,other,true)
99    end
100    for unicode, other in sortedhash(sub) do
101        add(unicode,other,false)
102    end
103end
104
105local specification = {
106    name        = "scripts",
107    description = "add superiors and inferiors",
108    manipulators = {
109        base = initialize,
110        node = initialize,
111    }
112}
113
114registerotffeature(specification)
115registerafmfeature(specification)
116
117-- a different kind of scripts support
118
119local function initialize(tfmdata,key,value)
120    if value then
121        local detail      = type(value) == "string" and settings_to_hash(value) or { }
122        local orientation = tonumber(detail.orientation) or 0
123        if orientation == 1 or orientation == 3 then
124           local characters = tfmdata.characters
125            local parameters = tfmdata.parameters
126            local emwidth    = parameters.quad
127            local exheight   = parameters.xheight
128            local ranges     = detail.ranges
129            local downshift  = exheight * (tonumber(detail.down) or 0)
130            local rightshift = exheight * (tonumber(detail.right) or 0)
131            local orientate
132            if orientation == 1 then
133                orientate = function(character)
134                    local width  = character.width or 0
135                    local height = character.height or 0
136                    local depth  = character.depth or 0
137                    character.width       = height + depth + rightshift + rightshift
138                    character.height      = width - downshift
139                    character.depth       = shift
140                    character.xoffset     = depth + rightshift
141                    character.yoffset     = width - downshift
142                    character.orientation = orientation
143                end
144            else
145                orientate = function(character)
146                    local width  = character.width or 0
147                    local height = character.height or 0
148                    local depth  = character.depth or 0
149--                     character.width       = height + depth + rightshift + rightshift
150                    character.height      = width - downshift
151                    character.depth       = shift
152--                     character.xoffset     = height + rightshift
153--                     character.yoffset     = - downshift
154--                     character.orientation = orientation
155                end
156            end
157            if ranges then
158                for s in gmatch(ranges,"[^, ]+") do
159                    local start, stop, description, gaps = getrange(s,true)
160                    if start and stop then
161                        for unicode=start,stop do
162                            local character = characters[unicode]
163                            if character then
164                                orientate(character)
165                            end
166                        end
167                    end
168                end
169            else
170                for unicode, character in next, characters do
171                    orientate(character)
172                end
173            end
174        end
175    end
176end
177
178local specification = {
179    name        = "vertical",
180    description = "vertical",
181    manipulators = {
182        base = initialize,
183        node = initialize,
184    }
185}
186
187registerotffeature(specification)
188registerafmfeature(specification)
189