font-imp-dimensions.lmt /size: 6991 b    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['font-imp-dimensions'] = {
2    version   = 1.001,
3    comment   = "companion to font-ini.mkiv and hand-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 next, type, tonumber = next, type, tonumber
10local ceil = math.ceil
11
12local fonts              = fonts
13local utilities          = utilities
14
15local helpers            = fonts.helpers
16local prependcommands    = helpers.prependcommands
17local charcommand        = helpers.commands.char
18local rightcommand       = helpers.commands.right
19
20local handlers           = fonts.handlers
21local otf                = handlers.otf
22local afm                = handlers.afm
23
24local registerotffeature = otf.features.register
25local registerafmfeature = afm.features.register
26
27local settings_to_array  = utilities.parsers.settings_to_array
28local gettexdimen        = tex.getdimen
29
30-- For Wolfgang Schuster:
31--
32-- \definefontfeature[thisway][default][script=hang,language=zhs,dimensions={2,2,2}]
33-- \definedfont[file:kozminpr6nregular*thisway]
34
35local function initialize(tfmdata,key,value)
36    if type(value) == "string" and value ~= "" then
37        local characters = tfmdata.characters
38        local parameters = tfmdata.parameters
39        local emwidth    = parameters.quad
40        local exheight   = parameters.xheight
41        local newwidth   = false
42        local newheight  = false
43        local newdepth   = false
44        local newshift   = false
45        if value == "strut" then
46            newheight = gettexdimen("strutht")
47            newdepth  = gettexdimen("strutdp")
48        elseif value == "mono" then
49            newwidth  = emwidth
50        elseif value == "halfmono" then
51            newwidth  = emwidth / 2
52        else
53            -- there are fonts out there with no x_height ...
54            local spec = settings_to_array(value)
55            newwidth  = spec[1]
56            newheight = spec[2]
57            newdepth  = spec[3]
58            newshift  = spec[4]
59            local quad      = parameters.quad      or 0
60            local ascender  = parameters.ascender  or 0
61            local descender = parameters.descender or 0
62            if newwidth  == "max" then
63                newwidth = quad
64            else
65                newwidth = tonumber(newwidth)
66                if newwidth then
67                    newwidth = newwidth * emwidth
68                end
69            end
70            if newheight == "max" then
71                newheight = ascender
72            else
73                newheight = tonumber(newheight)
74                if newheight then
75                    newheight = newheight * exheight
76                end
77            end
78            if newdepth == "max" then
79                newdepth = descender
80            else
81                newdepth = tonumber(newdepth)
82                if newdepth then
83                    newdepth  = newdepth  * exheight
84                end
85            end
86            if parameters.x_heigth == 0 then
87                -- maybe a fourth parameter
88                parameters.x_heigth = (ascender + descender) / 2
89            end
90        end
91        -- todo: hshift too
92        if newwidth or newheight or newdepth then
93            for unicode, character in next, characters do
94                local oldwidth  = character.width
95                local oldheight = character.height
96                local olddepth  = character.depth
97                local width  = newwidth  or oldwidth  or 0
98                local height = newheight or oldheight or 0
99                local depth  = newdepth  or olddepth  or 0
100                if oldwidth ~= width or oldheight ~= height or olddepth ~= depth then
101                    character.width  = width
102-- character.advance  = oldwidth
103                    character.height = height
104                    character.depth  = depth
105                    if oldwidth ~= width then
106                        -- todo: see below
107                        local commands = character.commands
108                        local hshift   = rightcommand[newshift or ((width - oldwidth) / 2)]
109                        if commands then
110                            character.commands = prependcommands (
111                                commands,
112                                hshift
113                            )
114                        else
115                            character.commands = {
116                                hshift,
117                                charcommand[unicode],
118                            }
119                        end
120                    end
121                end
122            end
123        end
124    end
125end
126
127local specification = {
128    name        = "dimensions",
129    description = "force dimensions",
130    manipulators = {
131        base = initialize,
132        node = initialize,
133    }
134}
135
136registerotffeature(specification)
137registerafmfeature(specification)
138
139local function initialize(tfmdata,key,value)
140    if value then
141        local characters = tfmdata.characters
142        local parameters = tfmdata.parameters
143        local emwidth    = parameters.quad
144        local factor     = parameters.size/655360
145        local fixedwidth = (tonumber(value) or 1)*factor*655360
146        parameters.space = 2*fixedwidth
147-- parameters.space = fixedwidth * ceil(parameters.space/fixedwidth)
148        for unicode, character in next, characters do
149            local oldwidth = character.width
150            if oldwidth ~= 0 then
151                local newwidth = false
152                if oldwidth > fixedwidth then
153                    newwidth = fixedwidth * ceil(oldwidth/fixedwidth)
154                elseif oldwidth < fixedwidth then
155                    newwidth = fixedwidth
156                end
157                if newwidth then
158                    character.width   = newwidth
159                    character.advance = oldwidth
160                    character.xoffset = (newwidth - oldwidth)/2
161                end
162            end
163        end
164    end
165end
166
167local specification = {
168    name        = "fixedwidth",
169    description = "force fixed widths",
170    manipulators = {
171        base = initialize,
172        node = initialize,
173    }
174}
175
176registerotffeature(specification)
177registerafmfeature(specification)
178
179-- local function initialize(tfmdata,key,value)
180--     if value then
181--         local resources = tfmdata.resources
182--         if resources then
183--             local marks = resources.marks -- markclasses marksets
184--             if marks then
185--                 local characters = tfmdata.characters
186--                 for k, v in next, marks do
187--                     characters[k].width = 0
188--                 end
189--             end
190--         end
191--     end
192-- end
193
194-- local specification = {
195--     name         = "zeromarks",
196--     description  = "zero width marks",
197--     manipulators = {
198--         base = initialize,
199--         node = initialize,
200--     }
201-- }
202
203-- registerotffeature(specification)
204