1if not modules then modules = { } end modules [ ' font-shp ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to font-ini.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 tonumber , next = tonumber , next
10local concat = table . concat
11local formatters = string . formatters
12
13local otf = fonts . handlers . otf
14local afm = fonts . handlers . afm
15local pfb = fonts . handlers . pfb
16
17local hashes = fonts . hashes
18local identifiers = hashes . identifiers
19
20local version = 0 . 009
21local shapescache = containers . define ( " fonts " , " shapes " , version , true )
22local streamscache = containers . define ( " fonts " , " streams " , version , true )
23
24
25
26local compact_streams = false
27
28directives . register ( " fonts.streams.compact " , function ( v ) compact_streams = v end )
29
30local function packoutlines ( data , makesequence )
31 local subfonts = data . subfonts
32 if subfonts then
33 for i = 1 , # subfonts do
34 packoutlines ( subfonts [ i ] , makesequence )
35 end
36 return
37 end
38 local common = data . segments
39 if common then
40 return
41 end
42 local glyphs = data . glyphs
43 if not glyphs then
44 return
45 end
46 if makesequence then
47 for index = 0 , # glyphs do
48 local glyph = glyphs [ index ]
49 if glyph then
50 local segments = glyph . segments
51 if segments then
52 local sequence = { }
53 local nofsequence = 0
54 for i = 1 , # segments do
55 local segment = segments [ i ]
56 local nofsegment = # segment
57
58 nofsequence = nofsequence + 1
59 sequence [ nofsequence ] = segment [ nofsegment ]
60 for i = 1 , nofsegment -1 do
61 nofsequence = nofsequence + 1
62 sequence [ nofsequence ] = segment [ i ]
63 end
64 end
65 glyph . sequence = sequence
66 glyph . segments = nil
67 end
68 end
69 end
70 else
71 local hash = { }
72 local common = { }
73 local reverse = { }
74 local last = 0
75 for index = 0 , # glyphs do
76 local glyph = glyphs [ index ]
77 if glyph then
78 local segments = glyph . segments
79 if segments then
80 for i = 1 , # segments do
81 local h = concat ( segments [ i ] , " " )
82 hash [ h ] = ( hash [ h ] or 0 ) + 1
83 end
84 end
85 end
86 end
87 for index = 0 , # glyphs do
88 local glyph = glyphs [ index ]
89 if glyph then
90 local segments = glyph . segments
91 if segments then
92 for i = 1 , # segments do
93 local segment = segments [ i ]
94 local h = concat ( segment , " " )
95 if hash [ h ] > 1 then
96 local idx = reverse [ h ]
97 if not idx then
98 last = last + 1
99 reverse [ h ] = last
100 common [ last ] = segment
101 idx = last
102 end
103 segments [ i ] = idx
104 end
105 end
106 end
107 end
108 end
109 if last > 0 then
110 data . segments = common
111 end
112 end
113end
114
115local function unpackoutlines ( data )
116 local subfonts = data . subfonts
117 if subfonts then
118 for i = 1 , # subfonts do
119 unpackoutlines ( subfonts [ i ] )
120 end
121 return
122 end
123 local common = data . segments
124 if not common then
125 return
126 end
127 local glyphs = data . glyphs
128 if not glyphs then
129 return
130 end
131 for index = 0 , # glyphs do
132 local glyph = glyphs [ index ]
133 if glyph then
134 local segments = glyph . segments
135 if segments then
136 for i = 1 , # segments do
137 local c = common [ segments [ i ] ]
138 if c then
139 segments [ i ] = c
140 end
141 end
142 end
143 end
144 end
145 data . segments = nil
146end
147
148
149
150local readers = otf . readers
151local cleanname = otf . readers . helpers . cleanname
152
153local function makehash ( filename , sub , instance )
154 local name = cleanname ( file . basename ( filename ) )
155 if instance then
156 return formatters [ " %s-%s-%s " ] ( name , sub or 0 , cleanname ( instance ) )
157 else
158 return formatters [ " %s-%s " ] ( name , sub or 0 )
159 end
160end
161
162local function loadoutlines ( cache , filename , sub , instance )
163 local base = file . basename ( filename )
164 local name = file . removesuffix ( base )
165 local kind = file . suffix ( filename )
166 local attr = lfs . attributes ( filename )
167 local size = attr and attr . size or 0
168 local time = attr and attr . modification or 0
169 local sub = tonumber ( sub )
170
171
172
173 if size > 0 and ( kind = = " otf " or kind = = " ttf " or kind = = " tcc " ) then
174 local hash = makehash ( filename , sub , instance )
175 data = containers . read ( cache , hash )
176 if not data or data . time ~ = time or data . size ~ = size then
177 data = otf . readers . loadshapes ( filename , sub , instance )
178 if data then
179 data . size = size
180 data . format = data . format or ( kind = = " otf " and " opentype " ) or " truetype "
181 data . time = time
182 packoutlines ( data )
183 containers . write ( cache , hash , data )
184 data = containers . read ( cache , hash )
185 end
186 end
187 unpackoutlines ( data )
188 elseif size > 0 and ( kind = = " pfb " ) then
189 local hash = containers . cleanname ( base )
190 data = containers . read ( cache , hash )
191 if not data or data . time ~ = time or data . size ~ = size then
192 data = afm . readers . loadshapes ( filename )
193 if data then
194 data . size = size
195 data . format = " type1 "
196 data . time = time
197 packoutlines ( data )
198 containers . write ( cache , hash , data )
199 data = containers . read ( cache , hash )
200 end
201 end
202 unpackoutlines ( data )
203 else
204 data = {
205 filename = filename ,
206 size = 0 ,
207 time = time ,
208 format = " unknown " ,
209 units = 1000 ,
210 glyphs = { }
211 }
212 end
213 return data
214end
215
216local function cachethem ( cache , hash , data )
217 containers . write ( cache , hash , data , compact_streams )
218 return containers . read ( cache , hash )
219end
220
221local function loadstreams ( cache , filename , sub , instance )
222 local base = file . basename ( filename )
223 local name = file . removesuffix ( base )
224 local kind = file . suffix ( filename )
225 local attr = lfs . attributes ( filename )
226 local size = attr and attr . size or 0
227 local time = attr and attr . modification or 0
228 local sub = tonumber ( sub )
229 if size > 0 and ( kind = = " otf " or kind = = " ttf " or kind = = " ttc " ) then
230 local hash = makehash ( filename , sub , instance )
231 data = containers . read ( cache , hash )
232 if not data or data . time ~ = time or data . size ~ = size then
233 data = otf . readers . loadshapes ( filename , sub , instance , true )
234 if data then
235 local glyphs = data . glyphs
236 local streams = { }
237 if glyphs then
238 for i = 0 , # glyphs do
239 local glyph = glyphs [ i ]
240 if glyph then
241 streams [ i ] = glyph . stream or " "
242 else
243 streams [ i ] = " "
244 end
245 end
246 end
247 data . streams = streams
248 data . glyphs = nil
249 data . size = size
250 data . format = data . format or ( kind = = " otf " and " opentype " ) or " truetype "
251 data . time = time
252 data = cachethem ( cache , hash , data )
253 end
254 end
255 elseif size > 0 and ( kind = = " pfb " ) then
256 local hash = makehash ( filename , sub , instance )
257 data = containers . read ( cache , hash )
258 if not data or data . time ~ = time or data . size ~ = size then
259 local names , encoding , streams , metadata = pfb . loadvector ( filename , false , true )
260 if streams then
261 local fontbbox = metadata . fontbbox or { 0 , 0 , 0 , 0 }
262 for i = 0 , # streams do
263 streams [ i ] = streams [ i ] . stream or " \14 "
264 end
265 data = {
266 filename = filename ,
267 size = size ,
268 time = time ,
269 format = " type1 " ,
270 streams = streams ,
271 fontheader = {
272 fontversion = metadata . version ,
273 units = 1000 ,
274 xmin = fontbbox [ 1 ] ,
275 ymin = fontbbox [ 2 ] ,
276 xmax = fontbbox [ 3 ] ,
277 ymax = fontbbox [ 4 ] ,
278 } ,
279 horizontalheader = {
280 ascender = 0 ,
281 descender = 0 ,
282 } ,
283 maximumprofile = {
284 nofglyphs = # streams + 1 ,
285 } ,
286 names = {
287 copyright = metadata . copyright ,
288 family = metadata . familyname ,
289 fullname = metadata . fullname ,
290 fontname = metadata . fontname ,
291 subfamily = metadata . subfamilyname ,
292 trademark = metadata . trademark ,
293 notice = metadata . notice ,
294 version = metadata . version ,
295 } ,
296 cffinfo = {
297 familyname = metadata . familyname ,
298 fullname = metadata . fullname ,
299 italicangle = metadata . italicangle ,
300 monospaced = metadata . isfixedpitch and true or false ,
301 underlineposition = metadata . underlineposition ,
302 underlinethickness = metadata . underlinethickness ,
303 weight = metadata . weight ,
304 } ,
305 }
306 data = cachethem ( cache , hash , data )
307 end
308 end
309 else
310 data = {
311 filename = filename ,
312 size = 0 ,
313 time = time ,
314 format = " unknown " ,
315 streams = { }
316 }
317 end
318 return data
319end
320
321local loadedshapes = { }
322local loadedstreams = { }
323
324local function loadoutlinedata ( fontdata , streams )
325 local properties = fontdata . properties
326 local filename = properties . filename
327 local subindex = fontdata . subindex
328 local instance = properties . instance
329 local hash = makehash ( filename , subindex , instance )
330 local loaded = loadedshapes [ hash ]
331 if not loaded then
332 loaded = loadoutlines ( shapescache , filename , subindex , instance )
333 loadedshapes [ hash ] = loaded
334 end
335 return loaded
336end
337
338hashes . shapes = table . setmetatableindex ( function ( t , k )
339 local f = identifiers [ k ]
340 if f then
341 return loadoutlinedata ( f )
342 end
343end )
344
345local function getstreamhash ( fontid )
346 local fontdata = identifiers [ fontid ]
347 if fontdata then
348 local properties = fontdata . properties
349 return makehash ( properties . filename , properties . subfont , properties . instance )
350 end
351end
352
353local function loadstreamdata ( fontdata )
354 local properties = fontdata . properties
355 local shared = fontdata . shared
356 local rawdata = shared and shared . rawdata
357 local metadata = rawdata and rawdata . metadata
358 local filename = properties . filename
359 local subindex = metadata and metadata . subfontindex
360 local instance = properties . instance
361 local hash = makehash ( filename , subindex , instance )
362 local loaded = loadedstreams [ hash ]
363 if not loaded then
364 loaded = loadstreams ( streamscache , filename , subindex , instance )
365 loadedstreams [ hash ] = loaded
366 end
367 return loaded
368end
369
370hashes . streams = table . setmetatableindex ( function ( t , k )
371 local f = identifiers [ k ]
372 if f then
373 return loadstreamdata ( f )
374 end
375end )
376
377otf . loadoutlinedata = loadoutlinedata
378otf . loadstreamdata = loadstreamdata
379otf . loadshapes = loadshapes
380otf . getstreamhash = getstreamhash
381
382local streams = fonts . hashes . streams
383
384
385
386callback . register ( " glyph_stream_provider " , function ( id , index , mode )
387 if id > 0 then
388 local streams = streams [ id ] . streams
389
390 if streams then
391 return streams [ index ] or " "
392 end
393 end
394 return " "
395end )
396 |