summaryrefslogtreecommitdiff
path: root/tex/context/base/m-punk.mkiv
blob: 051d51485ce0172c15f25e5c34523746ba736398 (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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
%D \module
%D   [       file=m-punk,
%D        version=2008.04.15,
%D          title=\CONTEXT\ Modules,
%D       subtitle=Punk Support,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright=PRAGMA]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

\ifx\luaversion\undefined \endinput \fi

% At some point the font generation code will move into the
% ConTeXt MkIV kernel.

\startluacode
do
    local concat   = table.concat
    local chardata = characters.data
    local fontdata = fonts.ids

    fonts.mp = fonts.mp or { }

    fonts.mp.version = fonts.mp.version or 1.11
    fonts.mp.inline  = true
    fonts.mp.cache   = containers.define("fonts", "mp", fonts.mp.version, true)

    metapost.characters = metapost.characters or { }

-- todo: use table share as in otf

    local characters, descriptions = { }, { }
    local factor, l, n, w, h, d, total, variants = 100, { }, 0, 0, 0, 0, 0, 0, true

    -- A next version of mplib will provide the tfm font information which
    -- gives better glyph dimensions, plus additional kerning information.

    local flusher = {
        startfigure = function(chrnum,llx,lly,urx,ury)
            l, n = { }, chrnum
            w, h, d = urx - llx, ury, -lly
            total = total + 1
            inline = fonts.mp.inline
        end,
        flushfigure = function(t)
            for i=1, #t do
                l[#l+1] = t[i]
            end
        end,
        stopfigure = function()
            local cd = chardata[n]
            if inline then
                descriptions[n] = {
                --  unicode = n,
                    name = cd and cd.adobename,
                    width = w*100,
                    height = h*100,
                    depth = d*100,
                    boundingbox = { 0, -d, w, h },
                }
                characters[n] = {
                    commands = { -- todo: xforms, should happen in backend
                        { "special", "pdf: " .. concat(l," ") },
                    }
                }
            else
                descriptions[n] = {
                --  unicode = n,
                    name = cd and cd.adobename,
                    width = w*100,
                    height = h*100,
                    depth = d*100,
                    boundingbox = { 0, -d, w, h },
                }
                characters[n] = {
                    commands = {
                        { "image", { stream = concat(l," "), bbox = { 0, -d*65536, w*65536, h*65536 } } },
                    }
                }
            end
        end
    }

    metapost.characters.instances = metapost.characters.instances or 10

    function metapost.characters.process(mpxformat, name, instances, scalefactor)
        statistics.starttiming(metapost.characters)
        scalefactor = scalefactor or 1
        instances = instances or metapost.characters.instances or 10
        local fontname = file.removesuffix(file.basename(name))
        local hash  = file.robustname(string.format("%s %05i %03i", fontname, scalefactor*1000, instances))
        local lists = containers.read(fonts.mp.cache, hash)
        if not lists then
            statistics.starttiming(flusher)
            -- we can use a format per font
            local data = io.loaddata(resolvers.find_file(name))
            metapost.reset(mpxformat)
            metapost.set_outer_color(2) -- no outer color and no reset either
            lists = { }
            for i=1,instances do
                list = { }
                characters, descriptions = { }, { }
                metapost.process(
                    mpxformat,
                    {
                        "randomseed := " .. i*10 .. ";",
                        "scale_factor := " .. scalefactor .. " ;",
                        data
                    },
                    false,
                    flusher
                )
                lists[i] = {
                    designsize = 655360,
                    name = string.format("%s-%03i",hash,i),
                    parameters = {
                        slant         =   0,
                        space         = 333   * scalefactor,
                        space_stretch = 166.5 * scalefactor,
                        space_shrink  = 111   * scalefactor,
                        x_height      = 431   * scalefactor,
                        quad          =1000   * scalefactor,
                        extra_space   =   0
                    },
                    ["type"] = "virtual",
                    characters = characters,
                    descriptions = descriptions,
                --  embedding = "subset",
                --  mkiv:
                    spacer = "space",
                    unit = 1000,
                    shared = { },
                    unique = { },
                }
            end
            metapost.reset(mpxformat) -- saves memory
            lists = containers.write(fonts.mp.cache, hash, lists)
            statistics.stoptiming(flusher)
        end
        variants = variants + #lists
        statistics.stoptiming(metapost.characters)
        return lists
    end

    function fonts.vf.aux.combine.commands.metafont(g,v)
        local size = g.specification.size
        local data = metapost.characters.process(v[2],v[3],v[4],size/655360)
        local list, t = { }, { }
        for d=1,#data do
            t = data[d]
            t = fonts.tfm.scale(t, -1000)
            local id = font.nextid()
            t.fonts = { { id = id } }
            fontdata[id] = t
            fonts.vf.aux.compose_characters(t)
            list[d] = font.define(t)
        end
        for k=1,#t do
            g[k] = t[k] -- kind of replace, when not present, make nil
        end
        g.virtualized = true
        g.variants = list
    end

    fonts.define.methods.install( "punk", {
        { "metafont", "mfplain", "punkfont.mp", 10 },
    } )

    cases.actions[99] = function(current)
        local used = fontdata[current.font].variants
        if used then
            local f = math.random(1,#used)
            current.font = used[f]
            return current, true
        else
            return current, false
        end
    end

    metapost.characters.flusher = flusher

    statistics.register("metapost font generation", function()
        local time = statistics.elapsedtime(flusher)
        if total > 0 then
            return string.format("%i glyphs, %.3f seconds runtime, %i glyphs/second", total, time, total/time)
        else
            return string.format("%i glyphs, %.3f seconds runtime", total, time)
        end
    end)

    statistics.register("metapost font loading",function()
        local time = statistics.elapsedtime(metapost.characters)
        if variants > 0 then
            return string.format("%.3f seconds, %i instances, %0.3f instances/second", time, variants, variants/time)
        else
            return string.format("%.3f seconds, %i instances", time, variants)
        end
    end)

end
\stopluacode

\unexpanded\def\EnableRandomPunk {\setcharactercasing[99]}
\unexpanded\def\RandomPunk       {\groupedcommand\EnableRandomPunk\donothing}
\unexpanded\def\StartRandomPunk  {\begingroup\EnableRandomPunk}
\unexpanded\def\StopRandomPunk   {\endgroup}

\starttypescript [serif] [punk] [default]
    \setups[font:fallback:serif] % no style variants yet
    \definefontsynonym [Serif] [demo@punk]
\stoptypescript

\starttypescript [punk]
    \definetypeface [punk] [rm] [serif] [punk] [default]
\stoptypescript

\definefontfeature[punknova][mode=node,script=latn,rand=yes,kern=yes,liga=yes,tlig=yes]

\starttypescript [serif] [punknova]
    \setups[font:fallback:serif] % no style variants yet, actually it's a sans
    \definefontsynonym [Serif] [file:punknova] [features=punknova]
\stoptypescript

\starttypescript [punknova]
    \definetypeface [punknova] [rm] [serif] [punknova] [default]
\stoptypescript

\endinput

\usetypescript[punk]

\setupbodyfont[punk,14pt]

\starttext
    \definedfont[demo@punk at 10pt]hello world\par
    \definedfont[demo@punk at 12pt]hello world\par
    \definedfont[demo@punk at 16pt]hello world\par
    \definedfont[demo@punk at 20pt]hello world\par
\stoptext