Check-in [3a564d3a11]
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Found cause of installation problem on Windows due to missing a string from the TTF name table. Along the way, improved the calculation of a number of head and hhea fields, and made a variety of other tweaks. The output is now a valid (if badly named) TTF file that covers 0-9, A-F and a few punctuation marks drawn with inter-digit dots.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:3a564d3a11849bbcdcd26035ce0f0a38b31033d1
User & Date: Ross 2015-12-23 02:39:01
Context
2015-12-23
18:33
Clean up some contours, restore the X in the .notdef glyph's box (which still should be redrawn without overlaps), and clean up some comments. check-in: 4ce1da6f02 user: Ross tags: trunk
02:39
Found cause of installation problem on Windows due to missing a string from the TTF name table. Along the way, improved the calculation of a number of head and hhea fields, and made a variety of other tweaks. The output is now a valid (if badly named) TTF file that covers 0-9, A-F and a few punctuation marks drawn with inter-digit dots. check-in: 3a564d3a11 user: Ross tags: trunk
2015-12-22
08:24
Made produced seven segment font pass all the tests of the Microsoft Font Verifier. The font, however, is still not acceptable to Windows either for Preview or Install. check-in: 402db317f0 user: Ross tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/Makefile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
all: dots.ttf dots.pdf



%.ttf: %.ttx
	ttx -o $@ $^

%.pdf: %.tex
	lualatex --interaction=nonstopmode $*.tex 
	lualatex --interaction=batchmode $*.tex

%.pdf: %.ttf
	fret -g -o $@ $^


testdots.pdf: testdots.tex dots.ttf
testdots.tex: testdots.txt
	pandoc --standalone --smart -f markdown --to latex -o $@ $*.txt





|












1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
all: dots.ttf dots.pdf



%.ttf: %.ttx
	ttx -f -o $@ $^

%.pdf: %.tex
	lualatex --interaction=nonstopmode $*.tex 
	lualatex --interaction=batchmode $*.tex

%.pdf: %.ttf
	fret -g -o $@ $^


testdots.pdf: testdots.tex dots.ttf
testdots.tex: testdots.txt
	pandoc --standalone --smart -f markdown --to latex -o $@ $*.txt

Changes to src/dotfonter.lua.

33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
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
    c=X{[0]='contour',
        {[0]='pt', x=640, y=446, on=1},
        {[0]='pt', x=640, y=2,   on=1},
        {[0]='pt', x=512, y=130, on=1},
        {[0]='pt', x=512, y=382, on=1},
    },
    d=X{[0]='contour',
        {[0]='pt', x=639, y=0, on=1},
        {[0]='pt', x=1,   y=0, on=1},
        {[0]='pt', x=129, y=128, on=1},
        {[0]='pt', x=511, y=128, on=1},
    },
    e=X{[0]='contour',
        {[0]='pt', x=0,   y=2,   on=1},
        {[0]='pt', x=0,   y=446, on=1},
        {[0]='pt', x=128, y=382, on=1},
        {[0]='pt', x=128, y=130, on=1},
................................................................................
        {[0]='pt', x=1,   y=448, on=1},
        {[0]='pt', x=129, y=512, on=1},
        {[0]='pt', x=511, y=512, on=1},
        {[0]='pt', x=639, y=448, on=1},
        {[0]='pt', x=511, y=384, on=1},
        {[0]='pt', x=129, y=384, on=1},
    },

















}

--[[ 
##seven segment character generator ROM for HEX digits

The segments are arranged as follows

    +-a-+
    f   b
    +-g-+
    e   c
    +-d-+


and usually coded with a on bit 0 through g on bit 6.

Because Lua likes strings, we use a simpler coding here where each 
character maps to a string contain a list of lit segments. From that
list, characters not in [a-g] will simply be ignored.

--]]
local rom = {
    ['0'] = {'abcdef ', n='zero'}, --0x3f,
    ['1'] = {' bc    ', n='one'},--0x06,
    ['2'] = {'ab de g', n='two'},--0x5b,
    ['3'] = {'abcd  g', n='three'},--0x4f,
    ['4'] = {' bc  fg', n='four'},--0x66,
    ['5'] = {'a cd fg', n='five'},--0x6d,
    ['6'] = {'a cdefg', n='six'}, --0x7d,
    ['7'] = {'abc    ', n='seven'}, --0x07,
    ['8'] = {'abcdefg', n='eight'}, --0x7f,
................................................................................
    ['9'] = {'abc  fg', n='nine'}, --0x67,
    ['A'] = 'abc efg', --0x77,
    ['B'] = '  cdefg', --0x7c,
    ['C'] = 'a  def ', --0x39,
    ['D'] = ' bcde g', --0x5e,
    ['E'] = 'a  defg', --0x79,
    ['F'] = 'a   efg', --0x71,





}

-- Run through the caracters in the rom and assemble a glyph for each
-- one and map in in the font.
for char,pat in pairs(rom) do
    local name = char
    if type(pat) == 'table' then
        pat,name = rom[char][1], rom[char].n
    end
    local g = X{[0]="TTGlyph", name=name,}
    for seg in ('abcdefg'):gmatch'.' do
        if pat:find(seg) then
            g[#g+1] = segments[seg]
        end
    end
    g[#g+1] = X{[0]='instructions',X{[0]='assembly'}}
    -- when placing the glyph, we also must include the metrics.
    -- For seven segments, the only character with non-zero lsb
    -- will be the digit '1' so we check for that and adjust.
    ttfont.PlaceGlyph(g, {width=1024, lsb= char=='1' and 512 or 0})
    ttfont.MapGlyph("unicode", char:byte(), name)
    if char:byte() <= 0x7f then
        ttfont.MapGlyph("mac", char:byte(), name)
    end
    ttfont.MapGlyph("win", char:byte(), name)
end

--[[ Adjust the strings.
--]]
ttfont.SetNames{
    vers='Version 001.042',
    copy='Copyright Lloyd Fingal 2015.',
    ffam='Upright Seven Segments',
    PSnm='UprightSevenSegments-Regular',

    demo='ABCDEF 0123456789',
}

-- get the finished font and write it as TTX
local font = ttfont.GetFont()
--print(font)
font:save("temp.ttx")







|

|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>









|

|
|
>









|







 







>
>
>
>
>





|

|


|
|







|











|


>







33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
..
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
    c=X{[0]='contour',
        {[0]='pt', x=640, y=446, on=1},
        {[0]='pt', x=640, y=2,   on=1},
        {[0]='pt', x=512, y=130, on=1},
        {[0]='pt', x=512, y=382, on=1},
    },
    d=X{[0]='contour',
        {[0]='pt', x=638, y=0, on=1},
        {[0]='pt', x=1,   y=0, on=1},
        {[0]='pt', x=130, y=128, on=1},
        {[0]='pt', x=511, y=128, on=1},
    },
    e=X{[0]='contour',
        {[0]='pt', x=0,   y=2,   on=1},
        {[0]='pt', x=0,   y=446, on=1},
        {[0]='pt', x=128, y=382, on=1},
        {[0]='pt', x=128, y=130, on=1},
................................................................................
        {[0]='pt', x=1,   y=448, on=1},
        {[0]='pt', x=129, y=512, on=1},
        {[0]='pt', x=511, y=512, on=1},
        {[0]='pt', x=639, y=448, on=1},
        {[0]='pt', x=511, y=384, on=1},
        {[0]='pt', x=129, y=384, on=1},
    },
    h=X{[0]='contour',
        {[0]='pt', x=704, y=0, on=1},
        {[0]='pt', x=704, y=126, on=1},
        {[0]='pt', x=830, y=126, on=1},
        {[0]='pt', x=830, y=0, on=1},
    },
    i=X{[0]='contour',
        {[0]='pt', x=704, y=-4, on=1},
        {[0]='pt', x=830, y=-4, on=1},
        {[0]='pt', x=704, y=-128, on=1},
    },
    j=X{[0]='contour',
        {[0]='pt', x=704, y=512, on=1},
        {[0]='pt', x=704, y=638, on=1},
        {[0]='pt', x=830, y=638, on=1},
        {[0]='pt', x=830, y=512, on=1},
    },
}

--[[ 
##seven segment character generator ROM for HEX digits

The segments are arranged as follows

    +-a-+
    f   b
    +-g-+ j
    e   c
    +-d-+ h
          i
          
and usually coded with a on bit 0 through g on bit 6.

Because Lua likes strings, we use a simpler coding here where each 
character maps to a string contain a list of lit segments. From that
list, characters not in [a-g] will simply be ignored.

--]]
local rom = {
    ['0'] = {'abcdef ', n='zero'}, --0x3f,
    ['1'] = {' bc    ', n='one', lsb=512},--0x06,
    ['2'] = {'ab de g', n='two'},--0x5b,
    ['3'] = {'abcd  g', n='three'},--0x4f,
    ['4'] = {' bc  fg', n='four'},--0x66,
    ['5'] = {'a cd fg', n='five'},--0x6d,
    ['6'] = {'a cdefg', n='six'}, --0x7d,
    ['7'] = {'abc    ', n='seven'}, --0x07,
    ['8'] = {'abcdefg', n='eight'}, --0x7f,
................................................................................
    ['9'] = {'abc  fg', n='nine'}, --0x67,
    ['A'] = 'abc efg', --0x77,
    ['B'] = '  cdefg', --0x7c,
    ['C'] = 'a  def ', --0x39,
    ['D'] = ' bcde g', --0x5e,
    ['E'] = 'a  defg', --0x79,
    ['F'] = 'a   efg', --0x71,
    ['.'] = {'h', n='period', lsb=704}, --0x80,
    [','] = {'hi', n='comma', lsb=704}, --0x180,
    [':'] = {'hj', n='colon', lsb=704}, --0x80,
    [';'] = {'hij', n='semicolon', lsb=704}, --0x180,
    ['#'] = {'abcdefghij', n='numbersign', lsb=0}, --0x3ff,
}

-- Run through the caracters in the rom and assemble a glyph for each
-- one and map in in the font.
for char,pat in pairs(rom) do
    local bars, name, lsb = pat, char, 0
    if type(pat) == 'table' then
        bars, name, lsb = pat[1], rom[char].n, rom[char].lsb or 0
    end
    local g = X{[0]="TTGlyph", name=name,}
    for seg in ('abcdefghij'):gmatch'.' do
        if bars:find(seg) then
            g[#g+1] = segments[seg]
        end
    end
    g[#g+1] = X{[0]='instructions',X{[0]='assembly'}}
    -- when placing the glyph, we also must include the metrics.
    -- For seven segments, the only character with non-zero lsb
    -- will be the digit '1' so we check for that and adjust.
    ttfont.PlaceGlyph(g, {width=1024, lsb=lsb, a = 896, d=-128})
    ttfont.MapGlyph("unicode", char:byte(), name)
    if char:byte() <= 0x7f then
        ttfont.MapGlyph("mac", char:byte(), name)
    end
    ttfont.MapGlyph("win", char:byte(), name)
end

--[[ Adjust the strings.
--]]
ttfont.SetNames{
    vers='Version 001.042',
    copy='Copyright Ross Berteig 2015.',
    ffam='Upright Seven Segments',
    PSnm='UprightSevenSegments-Regular',
    ufid='Upright Segments 1.042 '.. os.date"%Y%m%d-%H%M%S" ,
    demo='ABCDEF 0123456789',
}

-- get the finished font and write it as TTX
local font = ttfont.GetFont()
--print(font)
font:save("temp.ttx")

Changes to src/ttfname.lua.

10
11
12
13
14
15
16





17
18
19
20
21
22
23
...
113
114
115
116
117
118
119


120

121












122
123
124
125


126
127
128
129
130
131
132
found a clear statement of which strings are mandatory, and that might be
platform and consuming application dependent.

Indeces 1, 2, 3, 4, 6, 16, 17, 18 and 20 are all clearly intended to be 
seen or used by end users to choose this font by name. Index 19 ought to be 
used by anything that presents font specimins, but testing shows that Windows 
ignores it.






Index      Description
------     -------------
0          Copyright notice
1          Font Family name.
2          Font Subfamily name. Font style (italic, oblique) and 
           weight (light, bold, black, etc.). A font with no particular
................................................................................
    -- and contains tributes to two famous type designers and to the mathematician
    -- who described the parameterized curves used in TTF glyphs. It is also short
    -- enough at 38 characters.
    [19] =  'Mix Zapf with Veljovic and get quirky Beziers',
    [256] = 'Compiled by Dotfonter',
}





function M.BuildNameTable(ntab, platforms)












    defaults[4] = (ntab[1] or ntab.ffam or '')
        .. (ntab[2] or ntab.fsub or '')
        : gsub('Regular','')
        : gsub("(.+)"," %1")


    platforms = platforms or {
        {plat=1,enc=0,lang="0x0",unicode='True'},
        {plat=3,enc=1,lang="0x409"}
    }
    
    local name = xml.new{[0]="name"}
    for _,p in ipairs(platforms) do







>
>
>
>
>







 







>
>

>

>
>
>
>
>
>
>
>
>
>
>
>


|
|
>
>







10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
...
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
found a clear statement of which strings are mandatory, and that might be
platform and consuming application dependent.

Indeces 1, 2, 3, 4, 6, 16, 17, 18 and 20 are all clearly intended to be 
seen or used by end users to choose this font by name. Index 19 ought to be 
used by anything that presents font specimins, but testing shows that Windows 
ignores it.

According to [this answer at Stack Overflow](http://stackoverflow.com/a/21815641/68204) strings 3 and 6 are mandatory for a 
font to be installed (or even Previewed) in Windows, which was not clear from
any text in any of the TTF or OTF documentation.


Index      Description
------     -------------
0          Copyright notice
1          Font Family name.
2          Font Subfamily name. Font style (italic, oblique) and 
           weight (light, bold, black, etc.). A font with no particular
................................................................................
    -- and contains tributes to two famous type designers and to the mathematician
    -- who described the parameterized curves used in TTF glyphs. It is also short
    -- enough at 38 characters.
    [19] =  'Mix Zapf with Veljovic and get quirky Beziers',
    [256] = 'Compiled by Dotfonter',
}

--[[
--]]


function M.BuildNameTable(ntab, platforms)
    if not (ntab[1] or ntab.ffam) then 
        return error "Font must have a Font Family Name in the name table" 
    end
    if not (ntab[3] or ntab.ufid) then 
        return error "Font must have a unique ID in the name table" 
    end
    if not (ntab[6] or ntab.PSnm) then 
        return error "Font must have a PostScript Name in the name table" 
    end
    
    -- provide a standard full font name based on family and 
    -- subfamily per best practices.
    defaults[4] = (ntab[1] or ntab.ffam or '')
        .. (ntab[2] or ntab.fsub or '')
            : gsub('Regular','')
            : gsub("(.+)"," %1")
            
        
    platforms = platforms or {
        {plat=1,enc=0,lang="0x0",unicode='True'},
        {plat=3,enc=1,lang="0x409"}
    }
    
    local name = xml.new{[0]="name"}
    for _,p in ipairs(platforms) do

Changes to src/ttfont.lua.

39
40
41
42
43
44
45
46

47


48
49
50
51
52
53
54
..
65
66
67
68
69
70
71






72
73
74
75
76
77
78
...
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
...
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
...
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
--local ttfhmtx = require 'ttfhmtx'
--local ttfloca = require 'ttfloca' -- created entirely by the TTX compiler
local ttfmaxp = require 'ttfmaxp'
local ttfname = require 'ttfname'
local ttfpost = require 'ttfpost'
local ttfos_2 = require 'ttfos_2'



M.perEm = 1024



local tables = {}

-- Rember the order glyphs get created so that the TTF file 
-- will define them in the same order. This works by using the
-- table GlyphOrder defined by TTX for the purpose
tables.GlyphOrder = X"GlyphOrder"
................................................................................
    
    
    
function M.PlaceGlyph(glyph, t)
    tables.GlyphOrder:append{[0]="GlyphID", id=tables.nextid, name=glyph.name}
    tables.nextid = tables.nextid + 1
    tables.glyf:append(glyph)






    tables.hmtx:append{[0]='mtx', name=glyph.name, width=t.width, lsb=t.lsb}
end

-- standards recommmend that .notdef look like an empty box, a box 
-- with an X in it, or a box with a '?' in it. Because the diagonal 
-- lines will stand out from the dots making up all other glyphs more
-- than a plain box would, I've made it be a boxed X. A '?' would be
................................................................................
}
-- an empty glyph.
local nullglyph = xml.new{[0]="TTGlyph", name=".null" }
local crglyph = xml.new{[0]="TTGlyph", name="nonmarkingreturn" }
local spaceglyph = xml.new{[0]="TTGlyph", name="space" }

-- first four glyphs are recommended to be .notdef, .null, CR, and space
M.PlaceGlyph(notdefglyph, {width=1024, lsb=128})
M.PlaceGlyph(nullglyph, {width=0,lsb=0} )
M.PlaceGlyph(crglyph, {width=1024,lsb=0}) 
M.PlaceGlyph(spaceglyph, {width=1024,lsb=0})


--[[
#CMAP table is whole can of worms

The four mandatory glyphs have some special roles, and are usually expected
to be mapped in certain ways.  The cmap table holds all the views that map
................................................................................
    else
        tables.cmap[n]:append{[0]='map', code=('0x%x'):format(tonumber(m)), name=s}
    end
end

-- Unicode Map
setname(2, 0x20, 'space')

setname(2, 0x20AC, 'space') -- Unicode Euro

-- Mac 8-bit Map
-- Fill out all codes 0..255  
for i=0x1,0xff do 
    tables.cmap[3]:append{[0]='map', code=('0x%x'):format(tonumber(i)), name='.notdef'}
end
setname(3, 0x08, '.null')
setname(3, 0x1D, '.null')
setname(3, 0x0D, 'nonmarkingreturn')
setname(3, 0x09, 'space')
setname(3, 0x20, 'space')
setname(3, 0xA0, 'space')
setname(3, 0xDB, 'space') -- Mac Euro


-- Windows Unicode Map
setname(4, 0x20, 'space')
--setname(4, 0xFF, 'space')
setname(4, 0x20AC, 'space') -- Unicode Euro

function M.MapGlyph(map, code, name)
    local maps = {unicode=2, mac=3, win=4}
    map = maps[map] or tonumber(map)
    if not map then error"map not valid" end
    if map >= 2 and map <= 4 then
        setname(map, code, name)
    end
end


tables.name = ttfname.BuildNameTable{
    copy='Copyright Lloyd Fingal 2015.',

    ffam='Sample Silly Script',
    PSnm='SampleSillyScript-Regular',
--[=[    [1024]=[[
Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna 
aliqua. Ut enim ad minim veniam, quis nostrud exercitation 
ullamco laboris nisi ut aliquip ex ea commodo consequat. 
................................................................................
}

function M.SetNames(t)
    tables.name = ttfname.BuildNameTable(t)
end

function M.GetFont()
    tables.head = ttfhead.GetTable()

    ttfhhea.ascent = 896



    ttfhhea.descent = -128









    tables.hhea = ttfhhea.GetTable()
    tables.maxp = ttfmaxp.GetTable()
    tables.post = ttfpost.GetTable()
    tables.OS_2 = ttfos_2.GetTable()

    if not tables.loca then tables.loca = xml.new"loca" end


    if not tables.gasp then tables.gasp = xml.new"gasp" end
    tables.gasp:append(xml.new{[0]="gaspRange", rangeMaxPPEM=65535, rangeGaspBehavior=2})

    
    local font = xml.new{[0]="ttFont", sfntVersion="\\x00\\x01\\x00\\x00", ttLibVersion="3.0"}
    for _,tn in ipairs{'GlyphOrder','head','hhea','maxp',
        'OS_2','hmtx','cmap','loca','glyf','name','post', 'gasp'} do
        if tables[tn] then 
            font:append(tables[tn])
        end
    end
    return font
end


return M







<
>

>
>







 







>
>
>
>
>
>







 







|
|
|
|







 







>
|









|


|




|
|













>







 







<
>
|
>
>
>
|
>
>
>
>
>
>
>
>
>






>
>


>













39
40
41
42
43
44
45

46
47
48
49
50
51
52
53
54
55
56
..
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
...
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
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
...
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
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
--local ttfhmtx = require 'ttfhmtx'
--local ttfloca = require 'ttfloca' -- created entirely by the TTX compiler
local ttfmaxp = require 'ttfmaxp'
local ttfname = require 'ttfname'
local ttfpost = require 'ttfpost'
local ttfos_2 = require 'ttfos_2'


M.maxX, M.minX, M.maxY, M.minY = 0,0,0,0
M.perEm = 1024
M.head = ttfhead
M.hhea = ttfhhea

local tables = {}

-- Rember the order glyphs get created so that the TTF file 
-- will define them in the same order. This works by using the
-- table GlyphOrder defined by TTX for the purpose
tables.GlyphOrder = X"GlyphOrder"
................................................................................
    
    
    
function M.PlaceGlyph(glyph, t)
    tables.GlyphOrder:append{[0]="GlyphID", id=tables.nextid, name=glyph.name}
    tables.nextid = tables.nextid + 1
    tables.glyf:append(glyph)
    
    M.minX = M.minX < (t.lsb or 0) and M.minX or t.lsb
    M.maxX = M.maxX > (t.width or 0) and M.maxX or t.width
    M.minY = M.minY < (t.d or 0) and M.minY or t.d
    M.maxY = M.maxY > (t.a or 0) and M.maxY or t.a
    
    tables.hmtx:append{[0]='mtx', name=glyph.name, width=t.width, lsb=t.lsb}
end

-- standards recommmend that .notdef look like an empty box, a box 
-- with an X in it, or a box with a '?' in it. Because the diagonal 
-- lines will stand out from the dots making up all other glyphs more
-- than a plain box would, I've made it be a boxed X. A '?' would be
................................................................................
}
-- an empty glyph.
local nullglyph = xml.new{[0]="TTGlyph", name=".null" }
local crglyph = xml.new{[0]="TTGlyph", name="nonmarkingreturn" }
local spaceglyph = xml.new{[0]="TTGlyph", name="space" }

-- first four glyphs are recommended to be .notdef, .null, CR, and space
M.PlaceGlyph(notdefglyph, {width=1024, lsb=128, a=768, d=0})
M.PlaceGlyph(nullglyph, {width=0,lsb=0, a=0, d=0} )
M.PlaceGlyph(crglyph, {width=1024,lsb=0, a=0, d=0}) 
M.PlaceGlyph(spaceglyph, {width=1024,lsb=0, a=0, d=0})


--[[
#CMAP table is whole can of worms

The four mandatory glyphs have some special roles, and are usually expected
to be mapped in certain ways.  The cmap table holds all the views that map
................................................................................
    else
        tables.cmap[n]:append{[0]='map', code=('0x%x'):format(tonumber(m)), name=s}
    end
end

-- Unicode Map
setname(2, 0x20, 'space')
setname(2, 0xA0, 'space')
--setname(2, 0x20AC, 'space') -- Unicode Euro

-- Mac 8-bit Map
-- Fill out all codes 0..255  
for i=0x1,0xff do 
    tables.cmap[3]:append{[0]='map', code=('0x%x'):format(tonumber(i)), name='.notdef'}
end
setname(3, 0x08, '.null')
setname(3, 0x1D, '.null')
setname(3, 0x0D, 'nonmarkingreturn')
setname(3, 0x09, 'nonmarkingreturn')
setname(3, 0x20, 'space')
setname(3, 0xA0, 'space')
--setname(3, 0xDB, 'space') -- Mac Euro


-- Windows Unicode Map
setname(4, 0x20, 'space')
setname(4, 0xA0, 'space')
--setname(4, 0x20AC, 'space') -- Unicode Euro

function M.MapGlyph(map, code, name)
    local maps = {unicode=2, mac=3, win=4}
    map = maps[map] or tonumber(map)
    if not map then error"map not valid" end
    if map >= 2 and map <= 4 then
        setname(map, code, name)
    end
end


tables.name = ttfname.BuildNameTable{
    copy='Copyright Lloyd Fingal 2015.',
    ufid='xyzzy',
    ffam='Sample Silly Script',
    PSnm='SampleSillyScript-Regular',
--[=[    [1024]=[[
Lorem ipsum dolor sit amet, consectetur adipisicing elit, 
sed do eiusmod tempor incididunt ut labore et dolore magna 
aliqua. Ut enim ad minim veniam, quis nostrud exercitation 
ullamco laboris nisi ut aliquip ex ea commodo consequat. 
................................................................................
}

function M.SetNames(t)
    tables.name = ttfname.BuildNameTable(t)
end

function M.GetFont()

    
    ttfhhea.ascent = M.maxY
    ttfos_2.sTypoAscender = M.maxY
    ttfos_2.usWinAscent = M.maxY
    
    ttfhhea.descent = M.minY
    ttfos_2.sTypoDescender = M.minY
    ttfos_2.usWinDescent = math.abs(M.minY)
    
    ttfhhea.xMaxExtent = M.maxX
    ttfhhea.lineGap = 128
    ttfos_2.sTypoLineGap = 128


    tables.head = ttfhead.GetTable()
    tables.hhea = ttfhhea.GetTable()
    tables.maxp = ttfmaxp.GetTable()
    tables.post = ttfpost.GetTable()
    tables.OS_2 = ttfos_2.GetTable()

    if not tables.loca then tables.loca = xml.new"loca" end
    
    --[[
    if not tables.gasp then tables.gasp = xml.new"gasp" end
    tables.gasp:append(xml.new{[0]="gaspRange", rangeMaxPPEM=65535, rangeGaspBehavior=2})
    --]]
    
    local font = xml.new{[0]="ttFont", sfntVersion="\\x00\\x01\\x00\\x00", ttLibVersion="3.0"}
    for _,tn in ipairs{'GlyphOrder','head','hhea','maxp',
        'OS_2','hmtx','cmap','loca','glyf','name','post', 'gasp'} do
        if tables[tn] then 
            font:append(tables[tn])
        end
    end
    return font
end


return M