s-fonts-shapes.lua /size: 11 Kb    last modification: 2023-12-21 09:45
1if not modules then modules = { } end modules['s-fonts-shapes'] = {
2    version   = 1.001,
3    comment   = "companion to s-fonts-shapes.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
9moduledata.fonts        = moduledata.fonts        or { }
10moduledata.fonts.shapes = moduledata.fonts.shapes or { }
11
12local fontdata = fonts.hashes.identifiers
13
14local context = context
15local NC, NR = context.NC, context.NR
16local space, dontleavehmode, glyph, getvalue = context.space, context.dontleavehmode, context.glyph, context.getvalue
17local formatters = string.formatters
18
19function char(id,k)
20    dontleavehmode()
21    glyph(id,k)
22end
23
24local function special(id,specials)
25    if specials and #specials > 1 then
26        context("%s:",specials[1])
27        if #specials > 5 then
28            space() char(id,specials[2])
29            space() char(id,specials[3])
30            space() context("...")
31            space() char(id,specials[#specials-1])
32            space() char(id,specials[#specials])
33        else
34            for i=2,#specials do
35                space() char(id,specials[i])
36            end
37        end
38    end
39end
40
41function moduledata.fonts.shapes.showlist(specification) -- todo: ranges
42    specification = interfaces.checkedspecification(specification)
43    local id, cs = fonts.definers.internal(specification,"<module:fonts:shapes:font>")
44    local chrs = fontdata[id].characters
45    context.begingroup()
46    context.tt()
47    context.starttabulate { "|l|c|c|c|c|l|l|" }
48        context.FL()
49            NC() context.bold("unicode")
50            NC() context.bold("glyph")
51            NC() context.bold("shape")
52            NC() context.bold("lower")
53            NC() context.bold("upper")
54            NC() context.bold("specials")
55            NC() context.bold("description")
56            NC() NR()
57        context.TL()
58        for k, v in next, characters.data do
59            if chrs[k] then
60                NC() context("0x%05X",k)
61                NC() char(id,k)
62                NC() char(id,v.shcode)
63                NC() char(id,v.lccode or k)
64                NC() char(id,v.uccode or k)
65                NC() special(id,v.specials)
66                NC() context.tx(v.description)
67                NC() NR()
68            end
69        end
70    context.stoptabulate()
71    context.endgroup()
72end
73
74local descriptions = nil
75local characters   = nil
76
77
78local function showglyphshape(specification)
79    --
80    local specification = interfaces.checkedspecification(specification)
81    local id, cs        = fonts.definers.internal(specification,"<module:fonts:shapes:font>")
82    local tfmdata       = fontdata[id]
83    local characters    = tfmdata.characters
84    local descriptions  = tfmdata.descriptions
85    local parameters    = tfmdata.parameters
86    local tfmfactor     = parameters.scaledpoints/10
87-- inspect(tfmdata.parameters)
88-- inspect(tfmdata.properties)
89    local anchors       = fonts.helpers.collectanchors(tfmdata)
90
91    local function showonecharacter(unicode,krn,tight)
92        local c = characters  [unicode]
93        local d = descriptions[unicode]
94        if c and d then
95            local factor = (parameters.size/parameters.units)*((7200/7227)/65536)
96            local llx, lly, urx, ury = unpack(d.boundingbox)
97            local height = ury
98            local depth  = lly
99            llx, lly, urx, ury = llx*factor, lly*factor, urx*factor, ury*factor
100            local width  = (d.width or 0)*factor
101            context.start()
102            context.dontleavehmode()
103            context.obeyMPboxdepth()
104            context.startMPcode()
105            context("numeric lw ; lw := .125bp ;")
106            context("pickup pencircle scaled lw ;")
107            if width < 0.01 then
108                -- catches zero width marks
109                context('picture p ; p := textext.drt("\\hskip5sp\\getuvalue{%s}\\gray\\char%s"); draw p ;',cs,unicode)
110            else
111                context('picture p ; p := textext.drt("\\getuvalue{%s}\\gray\\char%s"); draw p ;',cs,unicode)
112            end
113            context('draw (%s,%s)--(%s,%s)--(%s,%s)--(%s,%s)--cycle withcolor green ;',llx,lly,urx,lly,urx,ury,llx,ury)
114            context('draw (%s,%s)--(%s,%s) withcolor green ;',llx,0,urx,0)
115            context('draw boundingbox p withcolor .2white withpen pencircle scaled .065bp ;')
116            context("defaultscale := 0.05 ; ")
117            -- inefficient but non critical
118            function slant(v,dx,dy,txt,xsign,ysign,loc,labloc,shift)
119                local n = #v
120                if n > 0 then
121                    local l = { }
122                    local t = { }
123                    for i=1,n do
124                        local c = v[i]
125                        local h = c.height or height or 0
126                        local d = depth or 0
127                        local k = c.kern or 0
128                        if i == 1 then
129                            l[1] = formatters["((%s,%s) shifted (%s,%s))"](xsign*k*factor,d*factor,dx,dy)
130                            t[1] = formatters['draw textext.%s("\\tttf(%s,%s)") scaled .025 shifted %s shifted (%i/4,%i/3);'](labloc,k,d,l[1],shift,shift);
131                        end
132                        l[i+1] = formatters["((%s,%s) shifted (%s,%s))"](xsign*k*factor,ysign*h*factor,dx,dy)
133                        t[i+1] = formatters['draw textext.%s("\\tttf(%s,%s)") scaled .025 shifted %s shifted (%i/4,%i/3);'](labloc,k,h,l[i+1],shift,shift);
134                    end
135                    context("draw laddered (%--t) withcolor .5white ;",l)
136                    for i=1,#l do
137                        context("draw %s withcolor blue withpen pencircle scaled 2lw ;",l[i])
138                        context(t[i])
139                    end
140                end
141            end
142            --
143            local math = d.math
144            if math then
145                local kerns = math.kerns
146                if kerns then
147                    for k, v in next, kerns do
148                        if k == "topright" and (krn == "all" or krn == k) then
149                            slant(v,width,0,k,1,1,"top","lrt",1)
150                        elseif k == "bottomright" and (krn == "all" or krn == k) then
151                            slant(v,width,0,k,1,1,"bot","ulft",-1)
152                        elseif k == "topleft" and (krn == "all" or krn == k) then
153                            slant(v,0,0,k,-1,1,"top","lrt",1)
154                        elseif k == "bottomleft" and (krn == "all" or krn == k) then
155                            slant(v,0,0,k,-1,1,"bot","ulft",-1)
156                        end
157                    end
158                end
159                local accent = math.topanchor or math.accent
160                if accent and accent ~= 0 then
161                    local a = accent * factor
162                    context('draw (%s,%s+1/4)--(%s,%s-1/4) withcolor blue;',a,ury,a,ury)
163                    context('draw textext.top("\\tttf%s") scaled .025 shifted (%s,%s+2/4);',accent,a,ury)
164                end
165            end
166            --
167            local anchordata = anchors[unicode]
168            if anchordata then
169                local function show(txt,list)
170                    if list then
171                        for i=1,#list do
172                            local li = list[i]
173                            local x, y = li[1], li[2]
174                            local xx, yy = x*factor, y*factor
175                            context("draw (%s,%s) withcolor blue withpen pencircle scaled 2lw ;",xx,yy)
176                            context('label.top("\\infofont %s",(%s,%s-2.75bp)) ;',txt .. i,xx,yy)
177                            context('label.bot("\\infofont (%s,%s)",(%s,%s+2.75bp)) ;',x,y,xx,yy)
178                        end
179                    end
180                end
181                --
182                show("b",anchordata.base)
183                show("m",anchordata.mark)
184                show("l",anchordata.ligature)
185                show("e",anchordata.entry)
186                show("x",anchordata.exit)
187            end
188            --
189            local italic = d.italic
190            if italic and italic ~= 0 then
191                local i = italic * factor
192                context('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue ;',width,ury,width,ury)
193                context('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue ;',width+i,ury,width+i,ury)
194                context('draw (%s,%s-1bp)--(%s,%s-1bp) withcolor blue ;',width,ury,width+i,ury)
195                context('label.lft("\\type{%s}",(%s+2bp,%s-1bp));',"italic",width,ury)
196                context('label.rt("%s",(%s-2bp,%s-1bp));',italic,width+i,ury)
197            end
198            context('draw origin withcolor red withpen pencircle scaled 2lw;')
199            local kern  = c.topright
200            if kern and kern ~= 0 then
201                local k = kern * factor / tfmfactor
202                context('draw (%s,%s) withcolor "orange" withpen pencircle scaled .2 ;',width+k,ury)
203            end
204            local kern  = c.bottomright
205            if kern and kern ~= 0 then
206                local k = kern * factor / tfmfactor
207                context('draw (%s,%s) withcolor "orange" withpen pencircle scaled .2 ;',width+k,lly)
208            end
209            local kern  = c.topleft
210            if kern and kern ~= 0 then
211                local k = kern * factor / tfmfactor
212                context('draw (%s,%s) withcolor "orange" withpen pencircle scaled .2 ;',-k,ury)
213            end
214            local kern  = c.bottomleft
215            if kern and kern ~= 0 then
216                local k = kern * factor / tfmfactor
217                context('draw (%s,%s) withcolor "orange" withpen pencircle scaled .2 ;',-k,lly)
218            end
219            if not tight then
220                context("setbounds currentpicture to boundingbox currentpicture enlarged 1bp ;")
221            end
222            context("currentpicture := currentpicture scaled 8 ;")
223            context.stopMPcode()
224            context.stop()
225        end
226    end
227
228    local unicode = tonumber(specification.character) or
229                    fonts.helpers.nametoslot(specification.character)
230
231    if unicode then
232        showonecharacter(unicode,"all",true)
233    else
234        context.modulefontsstartshowglyphshapes()
235        for unicode, description in fonts.iterators.descriptions(tfmdata) do
236            if unicode >= 0x110000 then
237                break
238            end
239            local kerns = specification.kerns
240            if kerns then
241                local k = description and description.math and description.math.kerns
242                if k then
243                    if not (kerns == "all" or k[kerns]) then
244                        goto DONE
245                    end
246                else
247                    goto DONE
248                end
249            end
250            context.modulefontsstartshowglyphshape(unicode,description.name or "",description.index or 0)
251                showonecharacter(unicode,kerns,false)
252            context.modulefontsstopshowglyphshape()
253          ::DONE::
254        end
255        context.modulefontsstopshowglyphshapes()
256    end
257
258end
259
260moduledata.fonts.shapes.showglyphshape    = showglyphshape
261moduledata.fonts.shapes.showallglypshapes = showglyphshape
262
263function moduledata.fonts.shapes.showlastglyphshapefield(unicode,name)
264    if not descriptions then
265        -- bad news
266    elseif name == "unicode" then
267        context("U+%05X",descriptions.unicode)
268    else
269        local d = descriptions[name]
270        if d then
271            context(d)
272        end
273    end
274end
275