1if not modules then modules = { } end modules ['meta-fnt'] = {
2 version = 1.001,
3 comment = "companion to meta-fnt.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 = next
10local concat = table.concat
11local format = string.format
12local formatters = string.formatters
13local chardata = characters.data
14local fontdata = fonts.hashes.identifiers
15local round = math.round
16
17local vffonts = fonts.handlers.vf
18
19local mpfonts = fonts.mp or { }
20fonts.mp = mpfonts
21
22mpfonts.version = mpfonts.version or 1.20
23mpfonts.inline = true
24mpfonts.cache = containers.define("fonts", "mp", mpfonts.version, true)
25
26metapost.fonts = metapost.fonts or { }
27
28local function unicodetoactualtext(...)
29 unicodetoactualtext = backends.codeinjections.unicodetoactualtext
30 return unicodetoactualtext(...)
31end
32
33
34
35local characters, descriptions = { }, { }
36local factor, code, slot, width, height, depth, total, variants, bbox, llx, lly, urx, ury = 100, { }, 0, 0, 0, 0, 0, 0, true, 0, 0, 0, 0
37
38local flusher = {
39 startfigure = function(_chr_,_llx_,_lly_,_urx_,_ury_)
40 code = { }
41 slot = _chr_
42 llx = _llx_
43 lly = _lly_
44 urx = _urx_
45 ury = _ury_
46 width = urx - llx
47 height = ury
48 depth = -lly
49 total = total + 1
50 inline = mpfonts.inline
51 end,
52 flushfigure = function(t)
53 for i=1,#t do
54 code[#code+1] = t[i]
55 end
56 end,
57 stopfigure = function()
58 local cd = chardata[n]
59 local code = unicodetoactualtext(slot,concat(code," ")) or ""
60 descriptions[slot] = {
61
62 name = cd and cd.adobename,
63 width = width * 100,
64 height = height * 100,
65 depth = depth * 100,
66 boundingbox = { llx, lly, urx, ury },
67 }
68 if inline then
69 characters[slot] = {
70 commands = {
71 { "pdf", "origin", code },
72 }
73 }
74 else
75 characters[slot] = {
76 commands = {
77 {
78 "image",
79 {
80 stream = code,
81 bbox = { 0, -depth * 65536, width * 65536, height * 65536 }
82 },
83 },
84 }
85 }
86 end
87 code = nil
88 end
89}
90
91local function process(mpxformat,name,instances,scalefactor)
92 local filename = resolvers.findfile(name)
93 local attributes = filename and lfs.isfile(filename) and lfs.attributes(filename)
94 if attributes then
95 statistics.starttiming(metapost.fonts)
96 scalefactor = scalefactor or 1
97 instances = instances or metapost.fonts.instances or 1
98 local fontname = file.removesuffix(file.basename(name))
99 local modification = attributes.modification
100 local filesize = attributes.size
101 local hash = file.robustname(formatters["%s %05i %03i"](fontname,round(scalefactor*1000),instances))
102 local lists = containers.read(mpfonts.cache,hash)
103 if not lists or lists.modification ~= modification or lists.filesize ~= filesize or lists.instances ~= instances or lists.scalefactor ~= scalefactor then
104 statistics.starttiming(flusher)
105 local data = io.loaddata(filename)
106 metapost.reset(mpxformat)
107 metapost.setoutercolor(2)
108 lists = { }
109 for i=1,instances do
110 characters = { }
111 descriptions = { }
112 metapost.process {
113 mpx = mpxformat,
114 flusher = flusher,
115 askedfig = "all",
116
117 data = {
118 formatters["randomseed := %s ;"](i*10),
119 formatters["charscale := %s ;"](scalefactor),
120 data,
121 },
122 }
123 lists[i] = {
124 characters = characters,
125 descriptions = descriptions,
126 parameters = {
127 designsize = 655360,
128 slant = 0,
129 space = 333 * scalefactor,
130 space_stretch = 166.5 * scalefactor,
131 space_shrink = 111 * scalefactor,
132 x_height = 431 * scalefactor,
133 quad = 1000 * scalefactor,
134 extra_space = 0,
135 },
136 properties = {
137 name = formatters["%s-%03i"](hash,i),
138 virtualized = true,
139 spacer = "space",
140 }
141 }
142 end
143 lists.version = metapost.variables.fontversion or "1.000"
144 lists.modification = modification
145 lists.filesize = filesize
146 lists.instances = instances
147 lists.scalefactor = scalefactor
148 metapost.reset(mpxformat)
149 lists = containers.write(mpfonts.cache, hash, lists)
150 statistics.stoptiming(flusher)
151 end
152 variants = variants + #lists
153 statistics.stoptiming(metapost.fonts)
154 return lists
155 else
156 return { }
157 end
158end
159
160metapost.fonts.flusher = flusher
161metapost.fonts.instances = 1
162metapost.fonts.process = process
163
164local function build(g,v)
165 local size = g.specification.size
166 local data = process(v[2],v[3],v[4],size/655360,v[6])
167 local list = { }
168 local t = { }
169 for d=1,#data do
170 t = fonts.constructors.scale(data[d],-1000)
171 local id = font.nextid()
172 t.fonts = { { id = id } }
173 fontdata[id] = t
174 if v[5] then
175 vffonts.helpers.composecharacters(t)
176 end
177 list[d] = font.define(t)
178 end
179 for k, v in next, t do
180 g[k] = v
181 end
182 g.properties.virtualized = true
183 g.variants = list
184end
185
186vffonts.combiner.commands.metapost = build
187vffonts.combiner.commands.metafont = build
188
189statistics.register("metapost font generation", function()
190 if total > 0 then
191 local time = statistics.elapsedtime(flusher)
192 if total > 0 then
193 return format("%i glyphs, %s seconds runtime, %.1f glyphs/second", total, time, total/tonumber(time))
194 else
195 return format("%i glyphs, %s seconds runtime", total, time)
196 end
197 end
198end)
199
200statistics.register("metapost font loading",function()
201 if variants > 0 then
202 local time = statistics.elapsedtime(metapost.fonts)
203 if variants > 0 then
204 return format("%s seconds, %i instances, %.3f instances/second", time, variants, variants/tonumber(time))
205 else
206 return format("%s seconds, %i instances", time, variants)
207 end
208 end
209end)
210
211
212
213
214
215
216
217
218
219
220
221local report = logs.reporter("metapost","fonts")
222
223function metapost.fonts.define(specification)
224 local fontname = specification.fontname or ""
225 local filename = specification.filename or ""
226 local format = specification.format or "metafun"
227 if fontname == "" then
228 report("no fontname given")
229 return
230 end
231 if filename == "" then
232 report("no filename given for %a",fontname)
233 return
234 end
235 local fullname = resolvers.findfile(filename)
236 if fullname == "" then
237 report("unable to locate file %a",filename)
238 return
239 end
240 report("generating font %a using format %a and file %a",fontname,format,filename)
241 fonts.definers.methods.install(fontname, {
242 {
243 specification.engine or "metapost",
244 format,
245 filename,
246 specification.instances or 1,
247 specification.compose or false,
248 },
249 } )
250end
251
252interfaces.implement {
253 name = "definemetafont",
254 actions = metapost.fonts.define,
255 arguments = {
256 {
257 { "fontname" },
258 { "filename" },
259 }
260 }
261}
262
263
264
265
266
267 |