summaryrefslogtreecommitdiff
path: root/src/fontloader/misc/fontloader-font-tfm.lua
blob: f790064813b5678894401e71ecc45a658c30faed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
if not modules then modules = { } end modules ['font-tfm'] = {
    version   = 1.001,
    comment   = "companion to font-ini.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

local next = next
local match = string.match

local trace_defining           = false  trackers.register("fonts.defining", function(v) trace_defining = v end)
local trace_features           = false  trackers.register("tfm.features",   function(v) trace_features = v end)

local report_defining          = logs.reporter("fonts","defining")
local report_tfm               = logs.reporter("fonts","tfm loading")

local findbinfile              = resolvers.findbinfile

local fonts                    = fonts
local handlers                 = fonts.handlers
local readers                  = fonts.readers
local constructors             = fonts.constructors
local encodings                = fonts.encodings

local tfm                      = constructors.newhandler("tfm")
tfm.version                    = 1.000
tfm.maxnestingdepth            = 5
tfm.maxnestingsize             = 65536*1024

local tfmfeatures              = constructors.newfeatures("tfm")
----- registertfmfeature       = tfmfeatures.register

constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua

fonts.formats.tfm              = "type1" -- we need to have at least a value here
fonts.formats.ofm              = "type1" -- we need to have at least a value here

--[[ldx--
<p>The next function encapsulates the standard <l n='tfm'/> loader as
supplied by <l n='luatex'/>.</p>
--ldx]]--

-- this might change: not scaling and then apply features and do scaling in the
-- usual way with dummy descriptions but on the other hand .. we no longer use
-- tfm so why bother

-- ofm directive blocks local path search unless set; btw, in context we
-- don't support ofm files anyway as this format is obsolete

-- we need to deal with nested virtual fonts, but because we load in the
-- frontend we also need to make sure we don't nest too deep (esp when sizes
-- get large)
--
-- (VTITLE Example of a recursion)
-- (MAPFONT D 0 (FONTNAME recurse)(FONTAT D 2))
-- (CHARACTER C A (CHARWD D 1)(CHARHT D 1)(MAP (SETRULE D 1 D 1)))
-- (CHARACTER C B (CHARWD D 2)(CHARHT D 2)(MAP (SETCHAR C A)))
-- (CHARACTER C C (CHARWD D 4)(CHARHT D 4)(MAP (SETCHAR C B)))
--
-- we added the same checks as below to the luatex engine

function tfm.setfeatures(tfmdata,features)
    local okay = constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm)
    if okay then
        return constructors.collectprocessors("tfm",tfmdata,features,trace_features,report_tfm)
    else
        return { } -- will become false
    end
end

local depth = { } -- table.setmetatableindex("number")

local function read_from_tfm(specification)
    local filename  = specification.filename
    local size      = specification.size
    depth[filename] = (depth[filename] or 0) + 1
    if trace_defining then
        report_defining("loading tfm file %a at size %s",filename,size)
    end
    local tfmdata = font.read_tfm(filename,size) -- not cached, fast enough
    if tfmdata then
        local features      = specification.features and specification.features.normal or { }
        local resources     = tfmdata.resources  or { }
        local properties    = tfmdata.properties or { }
        local parameters    = tfmdata.parameters or { }
        local shared        = tfmdata.shared     or { }
        properties.name     = tfmdata.name
        properties.fontname = tfmdata.fontname
        properties.psname   = tfmdata.psname
        properties.filename = specification.filename
        properties.format   = fonts.formats.tfm -- better than nothing
        parameters.size     = size
        --
        tfmdata.properties  = properties
        tfmdata.resources   = resources
        tfmdata.parameters  = parameters
        tfmdata.shared      = shared
        --
        shared.rawdata      = { }
        shared.features     = features
        shared.processes    = next(features) and tfm.setfeatures(tfmdata,features) or nil
        parameters.slant         = parameters.slant          or parameters[1] or 0
        parameters.space         = parameters.space          or parameters[2] or 0
        parameters.space_stretch = parameters.space_stretch  or parameters[3] or 0
        parameters.space_shrink  = parameters.space_shrink   or parameters[4] or 0
        parameters.x_height      = parameters.x_height       or parameters[5] or 0
        parameters.quad          = parameters.quad           or parameters[6] or 0
        parameters.extra_space   = parameters.extra_space    or parameters[7] or 0
        --
        constructors.enhanceparameters(parameters) -- official copies for us
        --
        if constructors.resolvevirtualtoo then
            fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here
            local vfname = findbinfile(specification.name, 'ovf')
            if vfname and vfname ~= "" then
                local vfdata = font.read_vf(vfname,size) -- not cached, fast enough
                if vfdata then
                    local chars = tfmdata.characters
                    for k,v in next, vfdata.characters do
                        chars[k].commands = v.commands
                    end
                    properties.virtualized = true
                    tfmdata.fonts = vfdata.fonts
                    tfmdata.type = "virtual" -- else nested calls with cummulative scaling
                    local fontlist = vfdata.fonts
                    local name = file.nameonly(filename)
                    for i=1,#fontlist do
                        local n = fontlist[i].name
                        local s = fontlist[i].size
                        local d = depth[filename]
                        s = constructors.scaled(s,vfdata.designsize)
                        if d > tfm.maxnestingdepth then
                            report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth)
                            fontlist[i] = { id = 0 }
                        elseif (d > 1) and (s > tfm.maxnestingsize) then
                            report_defining("virtual font %a exceeds size %s",n,s)
                            fontlist[i] = { id = 0 }
                        else
                            local t, id = fonts.constructors.readanddefine(n,s)
                            fontlist[i] = { id = id }
                        end
                    end
                end
            end
        end
        --
        local allfeatures = tfmdata.shared.features or specification.features.normal
        constructors.applymanipulators("tfm",tfmdata,allfeatures.normal,trace_features,report_tfm)
        if not features.encoding then
            local encoding, filename = match(properties.filename,"^(.-)%-(.*)$") -- context: encoding-name.*
            if filename and encoding and encodings.known and encodings.known[encoding] then
                features.encoding = encoding
            end
        end
        -- let's play safe:
        properties.haskerns     = true
        properties.hasligatures = true
        resources.unicodes      = { }
        resources.lookuptags    = { }
        --
        depth[filename] = depth[filename] - 1
        return tfmdata
    else
        depth[filename] = depth[filename] - 1
    end
end

local function check_tfm(specification,fullname) -- we could split up like afm/otf
    local foundname = findbinfile(fullname, 'tfm') or ""
    if foundname == "" then
        foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context
    end
    if foundname == "" then
        foundname = fonts.names.getfilename(fullname,"tfm") or ""
    end
    if foundname ~= "" then
        specification.filename = foundname
        specification.format   = "ofm"
        return read_from_tfm(specification)
    elseif trace_defining then
        report_defining("loading tfm with name %a fails",specification.name)
    end
end

readers.check_tfm = check_tfm

function readers.tfm(specification)
    local fullname = specification.filename or ""
    if fullname == "" then
        local forced = specification.forced or ""
        if forced ~= "" then
            fullname = specification.name .. "." .. forced
        else
            fullname = specification.name
        end
    end
    return check_tfm(specification,fullname)
end

readers.ofm = readers.tfm