1if not modules then modules = { } end modules [ ' font-dsp ' ] = {
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
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
57local next , type , tonumber = next , type , tonumber
58local band = bit32 . band
59local extract = bit32 . extract
60local bor = bit32 . bor
61local lshift = bit32 . lshift
62local rshift = bit32 . rshift
63local gsub = string . gsub
64local lower = string . lower
65local sub = string . sub
66local strip = string . strip
67local tohash = table . tohash
68local concat = table . concat
69local copy = table . copy
70local reversed = table . reversed
71local sort = table . sort
72local insert = table . insert
73local round = math . round
74
75local settings_to_hash = utilities . parsers . settings_to_hash_colon_too
76local setmetatableindex = table . setmetatableindex
77local formatters = string . formatters
78local sortedkeys = table . sortedkeys
79local sortedhash = table . sortedhash
80local sequenced = table . sequenced
81
82local report = logs . reporter ( " otf reader " )
83
84local readers = fonts . handlers . otf . readers
85local streamreader = readers . streamreader
86
87local setposition = streamreader . setposition
88local getposition = streamreader . getposition
89local readuinteger = streamreader . readcardinal1
90local readushort = streamreader . readcardinal2
91local readulong = streamreader . readcardinal4
92local readinteger = streamreader . readinteger1
93local readshort = streamreader . readinteger2
94local readstring = streamreader . readstring
95local readtag = streamreader . readtag
96local readbytes = streamreader . readbytes
97local readfixed = streamreader . readfixed4
98local read2dot14 = streamreader . read2dot14
99local skipshort = streamreader . skipshort
100local skipbytes = streamreader . skip
101local readbytetable = streamreader . readbytetable
102local readbyte = streamreader . readbyte
103local readcardinaltable = streamreader . readcardinaltable
104local readintegertable = streamreader . readintegertable
105local readfword = readshort
106
107local short = 2
108local ushort = 2
109local ulong = 4
110
111directives . register ( " fonts.streamreader " , function ( )
112
113 streamreader = utilities . streams
114
115 setposition = streamreader . setposition
116 getposition = streamreader . getposition
117 readuinteger = streamreader . readcardinal1
118 readushort = streamreader . readcardinal2
119 readulong = streamreader . readcardinal4
120 readinteger = streamreader . readinteger1
121 readshort = streamreader . readinteger2
122 readstring = streamreader . readstring
123 readtag = streamreader . readtag
124 readbytes = streamreader . readbytes
125 readfixed = streamreader . readfixed4
126 read2dot14 = streamreader . read2dot14
127 skipshort = streamreader . skipshort
128 skipbytes = streamreader . skip
129 readbytetable = streamreader . readbytetable
130 readbyte = streamreader . readbyte
131 readcardinaltable = streamreader . readcardinaltable
132 readintegertable = streamreader . readintegertable
133 readfword = readshort
134
135end )
136
137local gsubhandlers = { }
138local gposhandlers = { }
139
140readers . gsubhandlers = gsubhandlers
141readers . gposhandlers = gposhandlers
142
143local helpers = readers . helpers
144local gotodatatable = helpers . gotodatatable
145local setvariabledata = helpers . setvariabledata
146
147local lookupidoffset = -1
148
149local classes = {
150 " base " ,
151 " ligature " ,
152 " mark " ,
153 " component " ,
154}
155
156local gsubtypes = {
157 " single " ,
158 " multiple " ,
159 " alternate " ,
160 " ligature " ,
161 " context " ,
162 " chainedcontext " ,
163 " extension " ,
164 " reversechainedcontextsingle " ,
165}
166
167local gpostypes = {
168 " single " ,
169 " pair " ,
170 " cursive " ,
171 " marktobase " ,
172 " marktoligature " ,
173 " marktomark " ,
174 " context " ,
175 " chainedcontext " ,
176 " extension " ,
177}
178
179local chaindirections = {
180 context = 0 ,
181 chainedcontext = 1 ,
182 reversechainedcontextsingle = -1 ,
183}
184
185local function setmetrics ( data , where , tag , d )
186 local w = data [ where ]
187 if w then
188 local v = w [ tag ]
189 if v then
190
191
192 w [ tag ] = v + d
193 end
194 end
195end
196
197local variabletags = {
198 hasc = function ( data , d ) setmetrics ( data , " windowsmetrics " , " typoascender " , d ) end ,
199 hdsc = function ( data , d ) setmetrics ( data , " windowsmetrics " , " typodescender " , d ) end ,
200 hlgp = function ( data , d ) setmetrics ( data , " windowsmetrics " , " typolinegap " , d ) end ,
201 hcla = function ( data , d ) setmetrics ( data , " windowsmetrics " , " winascent " , d ) end ,
202 hcld = function ( data , d ) setmetrics ( data , " windowsmetrics " , " windescent " , d ) end ,
203 vasc = function ( data , d ) setmetrics ( data , " vhea not done " , " ascent " , d ) end ,
204 vdsc = function ( data , d ) setmetrics ( data , " vhea not done " , " descent " , d ) end ,
205 vlgp = function ( data , d ) setmetrics ( data , " vhea not done " , " linegap " , d ) end ,
206 xhgt = function ( data , d ) setmetrics ( data , " windowsmetrics " , " xheight " , d ) end ,
207 cpht = function ( data , d ) setmetrics ( data , " windowsmetrics " , " capheight " , d ) end ,
208 sbxs = function ( data , d ) setmetrics ( data , " windowsmetrics " , " subscriptxsize " , d ) end ,
209 sbys = function ( data , d ) setmetrics ( data , " windowsmetrics " , " subscriptysize " , d ) end ,
210 sbxo = function ( data , d ) setmetrics ( data , " windowsmetrics " , " subscriptxoffset " , d ) end ,
211 sbyo = function ( data , d ) setmetrics ( data , " windowsmetrics " , " subscriptyoffset " , d ) end ,
212 spxs = function ( data , d ) setmetrics ( data , " windowsmetrics " , " superscriptxsize " , d ) end ,
213 spys = function ( data , d ) setmetrics ( data , " windowsmetrics " , " superscriptysize " , d ) end ,
214 spxo = function ( data , d ) setmetrics ( data , " windowsmetrics " , " superscriptxoffset " , d ) end ,
215 spyo = function ( data , d ) setmetrics ( data , " windowsmetrics " , " superscriptyoffset " , d ) end ,
216 strs = function ( data , d ) setmetrics ( data , " windowsmetrics " , " strikeoutsize " , d ) end ,
217 stro = function ( data , d ) setmetrics ( data , " windowsmetrics " , " strikeoutpos " , d ) end ,
218 unds = function ( data , d ) setmetrics ( data , " postscript " , " underlineposition " , d ) end ,
219 undo = function ( data , d ) setmetrics ( data , " postscript " , " underlinethickness " , d ) end ,
220}
221
222local read_cardinal = {
223 streamreader . readcardinal1 ,
224 streamreader . readcardinal2 ,
225 streamreader . readcardinal3 ,
226 streamreader . readcardinal4 ,
227}
228
229local read_integer = {
230 streamreader . readinteger1 ,
231 streamreader . readinteger2 ,
232 streamreader . readinteger3 ,
233 streamreader . readinteger4 ,
234}
235
236
237
238
239
240
241
242local lookupnames = {
243 gsub = {
244 single = " gsub_single " ,
245 multiple = " gsub_multiple " ,
246 alternate = " gsub_alternate " ,
247 ligature = " gsub_ligature " ,
248 context = " gsub_context " ,
249 chainedcontext = " gsub_contextchain " ,
250 reversechainedcontextsingle = " gsub_reversecontextchain " ,
251 } ,
252 gpos = {
253 single = " gpos_single " ,
254 pair = " gpos_pair " ,
255 cursive = " gpos_cursive " ,
256 marktobase = " gpos_mark2base " ,
257 marktoligature = " gpos_mark2ligature " ,
258 marktomark = " gpos_mark2mark " ,
259 context = " gpos_context " ,
260 chainedcontext = " gpos_contextchain " ,
261 }
262}
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287local lookupflags = setmetatableindex ( function ( t , k )
288 local v = {
289 band ( k , 0x0008 ) ~ = 0 and true or false ,
290 band ( k , 0x0004 ) ~ = 0 and true or false ,
291 band ( k , 0x0002 ) ~ = 0 and true or false ,
292 band ( k , 0x0001 ) ~ = 0 and true or false ,
293 }
294 t [ k ] = v
295 return v
296end )
297
298
299
300
301
302
303
304
305
306
307local function axistofactors ( str )
308 local t = settings_to_hash ( str )
309 for k , v in next , t do
310 t [ k ] = tonumber ( v ) or v
311 end
312 return t
313end
314
315local hash = table . setmetatableindex ( function ( t , k )
316 local v = sequenced ( axistofactors ( k ) , " , " )
317 t [ k ] = v
318 return v
319end )
320
321helpers . normalizedaxishash = hash
322
323local cleanname = fonts . names and fonts . names . cleanname or function ( name )
324 return name and ( gsub ( lower ( name ) , " [^%a%d] " , " " ) ) or nil
325end
326
327helpers . cleanname = cleanname
328
329function helpers . normalizedaxis ( str )
330 return hash [ str ] or str
331end
332
333
334
335
336local function getaxisscale ( segments , minimum , default , maximum , user )
337
338
339
340 if not minimum or not default or not maximum then
341 return false
342 end
343 if user < minimum then
344 user = minimum
345 elseif user > maximum then
346 user = maximum
347 end
348 if user < default then
349 default = - ( default - user ) / ( default - minimum )
350 elseif user > default then
351 default = ( user - default ) / ( maximum - default )
352 else
353 default = 0
354 end
355 if not segments then
356 return default
357 end
358 local e
359 for i = 1 , # segments do
360 local s = segments [ i ]
361 if type ( s ) ~ = " number " then
362 report ( " using default axis scale " )
363 return default
364 elseif s [ 1 ] > = default then
365 if s [ 2 ] = = default then
366 return default
367 else
368 e = i
369 break
370 end
371 end
372 end
373 if e then
374 local b = segments [ e -1 ]
375 local e = segments [ e ]
376 return b [ 2 ] + ( e [ 2 ] - b [ 2 ] ) * ( default - b [ 1 ] ) / ( e [ 1 ] - b [ 1 ] )
377 else
378 return false
379 end
380end
381
382local function getfactors ( data , instancespec )
383 if instancespec = = true then
384
385 elseif type ( instancespec ) ~ = " string " or instancespec = = " " then
386 return
387 end
388 local variabledata = data . variabledata
389 if not variabledata then
390 return
391 end
392 local instances = variabledata . instances
393 local axis = variabledata . axis
394 local segments = variabledata . segments
395 if instances and axis then
396 local values
397 if instancespec = = true then
398
399
400
401 values = { }
402 for i = 1 , # axis do
403 values [ i ] = {
404
405 value = axis [ i ] . default ,
406 }
407 end
408
409 else
410 for i = 1 , # instances do
411 local instance = instances [ i ]
412 if cleanname ( instance . subfamily ) = = instancespec then
413 values = instance . values
414 break
415 end
416 end
417 end
418 if values then
419 local factors = { }
420 for i = 1 , # axis do
421 local a = axis [ i ]
422 factors [ i ] = getaxisscale ( segments , a . minimum , a . default , a . maximum , values [ i ] . value )
423 end
424 return factors
425 end
426 local values = axistofactors ( hash [ instancespec ] or instancespec )
427 if values then
428 local factors = { }
429 for i = 1 , # axis do
430 local a = axis [ i ]
431 local d = a . default
432 factors [ i ] = getaxisscale ( segments , a . minimum , d , a . maximum , values [ a . name or a . tag ] or d )
433 end
434 return factors
435 end
436 end
437end
438
439local function getscales ( regions , factors )
440 local scales = { }
441 for i = 1 , # regions do
442 local region = regions [ i ]
443 local s = 1
444 for j = 1 , # region do
445 local axis = region [ j ]
446 local f = factors [ j ]
447 local start = axis . start
448 local peak = axis . peak
449 local stop = axis . stop
450
451 if start > peak or peak > stop then
452
453 elseif start < 0 and stop > 0 and peak ~ = 0 then
454
455 elseif peak = = 0 then
456
457 elseif f < start or f > stop then
458
459 s = 0
460 break
461 elseif f < peak then
462
463 s = s * ( f - start ) / ( peak - start )
464 elseif f > peak then
465 s = s * ( stop - f ) / ( stop - peak )
466 else
467
468 end
469 end
470 scales [ i ] = s
471 end
472 return scales
473end
474
475helpers . getaxisscale = getaxisscale
476helpers . getfactors = getfactors
477helpers . getscales = getscales
478helpers . axistofactors = axistofactors
479
480local function readvariationdata ( f , storeoffset , factors )
481 local position = getposition ( f )
482 setposition ( f , storeoffset )
483
484 local format = readushort ( f )
485 local regionoffset = storeoffset + readulong ( f )
486 local nofdeltadata = readushort ( f )
487 local deltadata = readcardinaltable ( f , nofdeltadata , ulong )
488
489 setposition ( f , regionoffset )
490 local nofaxis = readushort ( f )
491 local nofregions = readushort ( f )
492 local regions = { }
493 for i = 1 , nofregions do
494 local t = { }
495 for i = 1 , nofaxis do
496 t [ i ] = {
497 start = read2dot14 ( f ) ,
498 peak = read2dot14 ( f ) ,
499 stop = read2dot14 ( f ) ,
500 }
501 end
502 regions [ i ] = t
503 end
504
505 if factors then
506 for i = 1 , nofdeltadata do
507 setposition ( f , storeoffset + deltadata [ i ] )
508 local nofdeltasets = readushort ( f )
509 local nofshorts = readushort ( f )
510 local nofregions = readushort ( f )
511 local usedregions = { }
512 local deltas = { }
513 for i = 1 , nofregions do
514 usedregions [ i ] = regions [ readushort ( f ) + 1 ]
515 end
516
517 for i = 1 , nofdeltasets do
518 local t = readintegertable ( f , nofshorts , short )
519 for i = nofshorts + 1 , nofregions do
520 t [ i ] = readinteger ( f )
521 end
522 deltas [ i ] = t
523 end
524 deltadata [ i ] = {
525 regions = usedregions ,
526 deltas = deltas ,
527 scales = factors and getscales ( usedregions , factors ) or nil ,
528 }
529 end
530 end
531 setposition ( f , position )
532 return regions , deltadata
533end
534
535helpers . readvariationdata = readvariationdata
536
537
538
539
540local function readcoverage ( f , offset , simple )
541 setposition ( f , offset )
542 local coverageformat = readushort ( f )
543 if coverageformat = = 1 then
544 local nofcoverage = readushort ( f )
545 if simple then
546
547 if nofcoverage = = 1 then
548 return { readushort ( f ) }
549 elseif nofcoverage = = 2 then
550 return { readushort ( f ) , readushort ( f ) }
551 else
552 return readcardinaltable ( f , nofcoverage , ushort )
553 end
554 elseif nofcoverage = = 1 then
555 return { [ readushort ( f ) ] = 0 }
556 elseif nofcoverage = = 2 then
557 return { [ readushort ( f ) ] = 0 , [ readushort ( f ) ] = 1 }
558 else
559 local coverage = { }
560 for i = 0 , nofcoverage -1 do
561 coverage [ readushort ( f ) ] = i
562 end
563 return coverage
564 end
565 elseif coverageformat = = 2 then
566 local nofranges = readushort ( f )
567 local coverage = { }
568 local n = simple and 1 or 0
569 for i = 1 , nofranges do
570 local firstindex = readushort ( f )
571 local lastindex = readushort ( f )
572 local coverindex = readushort ( f )
573 if simple then
574 for i = firstindex , lastindex do
575 coverage [ n ] = i
576 n = n + 1
577 end
578 else
579 for i = firstindex , lastindex do
580 coverage [ i ] = n
581 n = n + 1
582 end
583 end
584 end
585 return coverage
586 else
587 report ( " unknown coverage format %a " , coverageformat )
588 return { }
589 end
590end
591
592local function readclassdef ( f , offset , preset )
593 setposition ( f , offset )
594 local classdefformat = readushort ( f )
595 local classdef = { }
596 if type ( preset ) = = " number " then
597 for k = 0 , preset -1 do
598 classdef [ k ] = 1
599 end
600 end
601 if classdefformat = = 1 then
602 local index = readushort ( f )
603 local nofclassdef = readushort ( f )
604 for i = 1 , nofclassdef do
605 classdef [ index ] = readushort ( f ) + 1
606 index = index + 1
607 end
608 elseif classdefformat = = 2 then
609 local nofranges = readushort ( f )
610 local n = 0
611 for i = 1 , nofranges do
612 local firstindex = readushort ( f )
613 local lastindex = readushort ( f )
614 local class = readushort ( f ) + 1
615 for i = firstindex , lastindex do
616 classdef [ i ] = class
617 end
618 end
619 else
620 report ( " unknown classdef format %a " , classdefformat )
621 end
622 if type ( preset ) = = " table " then
623 for k in next , preset do
624 if not classdef [ k ] then
625 classdef [ k ] = 1
626 end
627 end
628 end
629 return classdef
630end
631
632local function classtocoverage ( defs )
633 if defs then
634 local list = { }
635 for index , class in next , defs do
636 local c = list [ class ]
637 if c then
638 c [ # c + 1 ] = index
639 else
640 list [ class ] = { index }
641 end
642 end
643 return list
644 end
645end
646
647
648
649local skips = { [ 0 ] =
650 0 ,
651 1 ,
652 1 ,
653 2 ,
654 1 ,
655 2 ,
656 2 ,
657 3 ,
658 2 ,
659 2 ,
660 3 ,
661 2 ,
662 3 ,
663 3 ,
664 4 ,
665}
666
667
668
669
670local function readvariation ( f , offset )
671 local p = getposition ( f )
672 setposition ( f , offset )
673 local outer = readushort ( f )
674 local inner = readushort ( f )
675 local format = readushort ( f )
676 setposition ( f , p )
677 if format = = 0x8000 then
678 return outer , inner
679 end
680end
681
682local function readposition ( f , format , mainoffset , getdelta )
683 if format = = 0 then
684 return false
685 end
686
687 if format = = 0x04 then
688 local h = readshort ( f )
689 if h = = 0 then
690 return true
691 else
692 return { 0 , 0 , h , 0 }
693 end
694 end
695 if format = = 0x05 then
696 local x = readshort ( f )
697 local h = readshort ( f )
698 if x = = 0 and h = = 0 then
699 return true
700 else
701 return { x , 0 , h , 0 }
702 end
703 end
704 if format = = 0x44 then
705 local h = readshort ( f )
706 if getdelta then
707 local d = readshort ( f )
708 if d > 0 then
709 local outer , inner = readvariation ( f , mainoffset + d )
710 if outer then
711 h = h + getdelta ( outer , inner )
712 end
713 end
714 else
715 skipshort ( f , 1 )
716 end
717 if h = = 0 then
718 return true
719 else
720 return { 0 , 0 , h , 0 }
721 end
722 end
723
724
725
726
727
728
729
730
731
732 local x = band ( format , 0x1 ) ~ = 0 and readshort ( f ) or 0
733 local y = band ( format , 0x2 ) ~ = 0 and readshort ( f ) or 0
734 local h = band ( format , 0x4 ) ~ = 0 and readshort ( f ) or 0
735 local v = band ( format , 0x8 ) ~ = 0 and readshort ( f ) or 0
736 if format > = 0x10 then
737 local X = band ( format , 0x10 ) ~ = 0 and skipshort ( f ) or 0
738 local Y = band ( format , 0x20 ) ~ = 0 and skipshort ( f ) or 0
739 local H = band ( format , 0x40 ) ~ = 0 and skipshort ( f ) or 0
740 local V = band ( format , 0x80 ) ~ = 0 and skipshort ( f ) or 0
741 local s = skips [ extract ( format , 4 , 4 ) ]
742 if s > 0 then
743 skipshort ( f , s )
744 end
745 if getdelta then
746 if X > 0 then
747 local outer , inner = readvariation ( f , mainoffset + X )
748 if outer then
749 x = x + getdelta ( outer , inner )
750 end
751 end
752 if Y > 0 then
753 local outer , inner = readvariation ( f , mainoffset + Y )
754 if outer then
755 y = y + getdelta ( outer , inner )
756 end
757 end
758 if H > 0 then
759 local outer , inner = readvariation ( f , mainoffset + H )
760 if outer then
761 h = h + getdelta ( outer , inner )
762 end
763 end
764 if V > 0 then
765 local outer , inner = readvariation ( f , mainoffset + V )
766 if outer then
767 v = v + getdelta ( outer , inner )
768 end
769 end
770 end
771 return { x , y , h , v }
772 elseif x = = 0 and y = = 0 and h = = 0 and v = = 0 then
773 return true
774 else
775 return { x , y , h , v }
776 end
777end
778
779local function readanchor ( f , offset , getdelta )
780 if not offset or offset = = 0 then
781 return nil
782 end
783 setposition ( f , offset )
784
785 local format = readshort ( f )
786 local x = readshort ( f )
787 local y = readshort ( f )
788 if format = = 3 then
789 if getdelta then
790 local X = readshort ( f )
791 local Y = readshort ( f )
792 if X > 0 then
793 local outer , inner = readvariation ( f , offset + X )
794 if outer then
795 x = x + getdelta ( outer , inner )
796 end
797 end
798 if Y > 0 then
799 local outer , inner = readvariation ( f , offset + Y )
800 if outer then
801 y = y + getdelta ( outer , inner )
802 end
803 end
804 else
805 skipshort ( f , 2 )
806 end
807 return { x , y }
808 else
809 return { x , y }
810 end
811end
812
813
814
815
816local function readfirst ( f , offset )
817 if offset then
818 setposition ( f , offset )
819 end
820 return { readushort ( f ) }
821end
822
823
824
825function readarray ( f , offset )
826 if offset then
827 setposition ( f , offset )
828 end
829 local n = readushort ( f )
830 if n = = 1 then
831 return { readushort ( f ) } , 1
832 elseif n > 0 then
833 return readcardinaltable ( f , n , ushort ) , n
834 end
835end
836
837local function readcoveragearray ( f , offset , t , simple )
838 if not t then
839 return nil
840 end
841 local n = # t
842 if n = = 0 then
843 return nil
844 end
845 for i = 1 , n do
846 t [ i ] = readcoverage ( f , offset + t [ i ] , simple )
847 end
848 return t
849end
850
851local function covered ( subset , all )
852 local used , u
853 for i = 1 , # subset do
854 local s = subset [ i ]
855 if all [ s ] then
856 if used then
857 u = u + 1
858 used [ u ] = s
859 else
860 u = 1
861 used = { s }
862 end
863 end
864 end
865 return used
866end
867
868
869
870
871
872
873local function readlookuparray ( f , noflookups , nofcurrent )
874 local lookups = { }
875 if noflookups > 0 then
876 local length = 0
877 for i = 1 , noflookups do
878 local index = readushort ( f ) + 1
879 if index > length then
880 length = index
881 end
882 local lookup = readushort ( f ) + 1
883 local list = lookups [ index ]
884 if list then
885 list [ # list + 1 ] = lookup
886 else
887 lookups [ index ] = { lookup }
888 end
889 end
890 for index = 1 , length do
891 if not lookups [ index ] then
892 lookups [ index ] = false
893 end
894 end
895
896
897
898 end
899 return lookups
900end
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923local function unchainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , what )
924 local tableoffset = lookupoffset + offset
925 setposition ( f , tableoffset )
926 local subtype = readushort ( f )
927 if subtype = = 1 then
928 local coverage = readushort ( f )
929 local subclasssets = readarray ( f )
930 local rules = { }
931 if subclasssets then
932 coverage = readcoverage ( f , tableoffset + coverage , true )
933 for i = 1 , # subclasssets do
934 local offset = subclasssets [ i ]
935 if offset > 0 then
936 local firstcoverage = coverage [ i ]
937 local rulesoffset = tableoffset + offset
938 local subclassrules = readarray ( f , rulesoffset )
939 for rule = 1 , # subclassrules do
940 setposition ( f , rulesoffset + subclassrules [ rule ] )
941 local nofcurrent = readushort ( f )
942 local noflookups = readushort ( f )
943 local current = { { firstcoverage } }
944 for i = 2 , nofcurrent do
945 current [ i ] = { readushort ( f ) }
946 end
947 local lookups = readlookuparray ( f , noflookups , nofcurrent )
948 rules [ # rules + 1 ] = {
949 current = current ,
950 lookups = lookups
951 }
952 end
953 end
954 end
955 else
956 report ( " empty subclassset in %a subtype %i " , " unchainedcontext " , subtype )
957 end
958 return {
959 format = " glyphs " ,
960 rules = rules ,
961 }
962 elseif subtype = = 2 then
963
964
965 local coverage = readushort ( f )
966 local currentclassdef = readushort ( f )
967 local subclasssets = readarray ( f )
968 local rules = { }
969 if subclasssets then
970 coverage = readcoverage ( f , tableoffset + coverage )
971 currentclassdef = readclassdef ( f , tableoffset + currentclassdef , coverage )
972 local currentclasses = classtocoverage ( currentclassdef , fontdata . glyphs )
973 for class = 1 , # subclasssets do
974 local offset = subclasssets [ class ]
975 if offset > 0 then
976 local firstcoverage = currentclasses [ class ]
977 if firstcoverage then
978 firstcoverage = covered ( firstcoverage , coverage )
979 if firstcoverage then
980 local rulesoffset = tableoffset + offset
981 local subclassrules = readarray ( f , rulesoffset )
982 for rule = 1 , # subclassrules do
983 setposition ( f , rulesoffset + subclassrules [ rule ] )
984 local nofcurrent = readushort ( f )
985 local noflookups = readushort ( f )
986 local current = { firstcoverage }
987 for i = 2 , nofcurrent do
988 current [ i ] = currentclasses [ readushort ( f ) + 1 ]
989 end
990 local lookups = readlookuparray ( f , noflookups , nofcurrent )
991 rules [ # rules + 1 ] = {
992 current = current ,
993 lookups = lookups
994 }
995 end
996 else
997 report ( " no coverage " )
998 end
999 else
1000 report ( " no coverage class " )
1001 end
1002 end
1003 end
1004 else
1005 report ( " empty subclassset in %a subtype %i " , " unchainedcontext " , subtype )
1006 end
1007 return {
1008 format = " class " ,
1009 rules = rules ,
1010 }
1011 elseif subtype = = 3 then
1012 local nofglyphs = readushort ( f )
1013 local noflookups = readushort ( f )
1014 local current = readcardinaltable ( f , nofglyphs , ushort )
1015 local lookups = readlookuparray ( f , noflookups , # current )
1016 current = readcoveragearray ( f , tableoffset , current , true )
1017 return {
1018 format = " coverage " ,
1019 rules = {
1020 {
1021 current = current ,
1022 lookups = lookups ,
1023 }
1024 }
1025 }
1026 else
1027 report ( " unsupported subtype %a in %a %s " , subtype , " unchainedcontext " , what )
1028 end
1029end
1030
1031
1032
1033
1034
1035local function chainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , what )
1036 local tableoffset = lookupoffset + offset
1037 setposition ( f , tableoffset )
1038 local subtype = readushort ( f )
1039 if subtype = = 1 then
1040 local coverage = readushort ( f )
1041 local subclasssets = readarray ( f )
1042 local rules = { }
1043 if subclasssets then
1044 coverage = readcoverage ( f , tableoffset + coverage , true )
1045 for i = 1 , # subclasssets do
1046 local offset = subclasssets [ i ]
1047 if offset > 0 then
1048 local firstcoverage = coverage [ i ]
1049 local rulesoffset = tableoffset + offset
1050 local subclassrules = readarray ( f , rulesoffset )
1051 for rule = 1 , # subclassrules do
1052 setposition ( f , rulesoffset + subclassrules [ rule ] )
1053 local nofbefore = readushort ( f )
1054 local before
1055 if nofbefore > 0 then
1056 before = { }
1057 for i = 1 , nofbefore do
1058 before [ i ] = { readushort ( f ) }
1059 end
1060 end
1061 local nofcurrent = readushort ( f )
1062 local current = { { firstcoverage } }
1063 for i = 2 , nofcurrent do
1064 current [ i ] = { readushort ( f ) }
1065 end
1066 local nofafter = readushort ( f )
1067 local after
1068 if nofafter > 0 then
1069 after = { }
1070 for i = 1 , nofafter do
1071 after [ i ] = { readushort ( f ) }
1072 end
1073 end
1074 local noflookups = readushort ( f )
1075 local lookups = readlookuparray ( f , noflookups , nofcurrent )
1076 rules [ # rules + 1 ] = {
1077 before = before ,
1078 current = current ,
1079 after = after ,
1080 lookups = lookups ,
1081 }
1082 end
1083 end
1084 end
1085 else
1086 report ( " empty subclassset in %a subtype %i " , " chainedcontext " , subtype )
1087 end
1088 return {
1089 format = " glyphs " ,
1090 rules = rules ,
1091 }
1092 elseif subtype = = 2 then
1093 local coverage = readushort ( f )
1094 local beforeclassdef = readushort ( f )
1095 local currentclassdef = readushort ( f )
1096 local afterclassdef = readushort ( f )
1097 local subclasssets = readarray ( f )
1098 local rules = { }
1099 if subclasssets then
1100 local coverage = readcoverage ( f , tableoffset + coverage )
1101 local beforeclassdef = readclassdef ( f , tableoffset + beforeclassdef , nofglyphs )
1102 local currentclassdef = readclassdef ( f , tableoffset + currentclassdef , coverage )
1103 local afterclassdef = readclassdef ( f , tableoffset + afterclassdef , nofglyphs )
1104 local beforeclasses = classtocoverage ( beforeclassdef , fontdata . glyphs )
1105 local currentclasses = classtocoverage ( currentclassdef , fontdata . glyphs )
1106 local afterclasses = classtocoverage ( afterclassdef , fontdata . glyphs )
1107 for class = 1 , # subclasssets do
1108 local offset = subclasssets [ class ]
1109 if offset > 0 then
1110 local firstcoverage = currentclasses [ class ]
1111 if firstcoverage then
1112 firstcoverage = covered ( firstcoverage , coverage )
1113 if firstcoverage then
1114 local rulesoffset = tableoffset + offset
1115 local subclassrules = readarray ( f , rulesoffset )
1116 for rule = 1 , # subclassrules do
1117
1118
1119 setposition ( f , rulesoffset + subclassrules [ rule ] )
1120 local nofbefore = readushort ( f )
1121 local before
1122 if nofbefore > 0 then
1123 before = { }
1124 for i = 1 , nofbefore do
1125 before [ i ] = beforeclasses [ readushort ( f ) + 1 ]
1126 end
1127 end
1128 local nofcurrent = readushort ( f )
1129 local current = { firstcoverage }
1130 for i = 2 , nofcurrent do
1131 current [ i ] = currentclasses [ readushort ( f ) + 1 ]
1132 end
1133 local nofafter = readushort ( f )
1134 local after
1135 if nofafter > 0 then
1136 after = { }
1137 for i = 1 , nofafter do
1138 after [ i ] = afterclasses [ readushort ( f ) + 1 ]
1139 end
1140 end
1141
1142 local noflookups = readushort ( f )
1143 local lookups = readlookuparray ( f , noflookups , nofcurrent )
1144 rules [ # rules + 1 ] = {
1145 before = before ,
1146 current = current ,
1147 after = after ,
1148 lookups = lookups ,
1149 }
1150 end
1151 else
1152 report ( " no coverage " )
1153 end
1154 else
1155 report ( " class is not covered " )
1156 end
1157 end
1158 end
1159 else
1160 report ( " empty subclassset in %a subtype %i " , " chainedcontext " , subtype )
1161 end
1162 return {
1163 format = " class " ,
1164 rules = rules ,
1165 }
1166 elseif subtype = = 3 then
1167 local before = readarray ( f )
1168 local current = readarray ( f )
1169 local after = readarray ( f )
1170 local noflookups = readushort ( f )
1171 local lookups = readlookuparray ( f , noflookups , # current )
1172 before = readcoveragearray ( f , tableoffset , before , true )
1173 current = readcoveragearray ( f , tableoffset , current , true )
1174 after = readcoveragearray ( f , tableoffset , after , true )
1175 return {
1176 format = " coverage " ,
1177 rules = {
1178 {
1179 before = before ,
1180 current = current ,
1181 after = after ,
1182 lookups = lookups ,
1183 }
1184 }
1185 }
1186 else
1187 report ( " unsupported subtype %a in %a %s " , subtype , " chainedcontext " , what )
1188 end
1189end
1190
1191local function extension ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , types , handlers , what )
1192 local tableoffset = lookupoffset + offset
1193 setposition ( f , tableoffset )
1194 local subtype = readushort ( f )
1195 if subtype = = 1 then
1196 local lookuptype = types [ readushort ( f ) ]
1197 local faroffset = readulong ( f )
1198 local handler = handlers [ lookuptype ]
1199 if handler then
1200
1201 return handler ( f , fontdata , lookupid , tableoffset + faroffset , 0 , glyphs , nofglyphs ) , lookuptype
1202 else
1203 report ( " no handler for lookuptype %a subtype %a in %s %s " , lookuptype , subtype , what , " extension " )
1204 end
1205 else
1206 report ( " unsupported subtype %a in %s %s " , subtype , what , " extension " )
1207 end
1208end
1209
1210
1211
1212function gsubhandlers . single ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1213 local tableoffset = lookupoffset + offset
1214 setposition ( f , tableoffset )
1215 local subtype = readushort ( f )
1216 if subtype = = 1 then
1217 local coverage = readushort ( f )
1218 local delta = readshort ( f )
1219 local coverage = readcoverage ( f , tableoffset + coverage )
1220 for index in next , coverage do
1221 local newindex = ( index + delta ) % 65536
1222 if index > nofglyphs or newindex > nofglyphs then
1223 report ( " invalid index in %s format %i: %i -> %i (max %i) " , " single " , subtype , index , newindex , nofglyphs )
1224 coverage [ index ] = nil
1225 else
1226 coverage [ index ] = newindex
1227 end
1228 end
1229 return {
1230 coverage = coverage
1231 }
1232 elseif subtype = = 2 then
1233 local coverage = readushort ( f )
1234 local nofreplacements = readushort ( f )
1235 local replacements = readcardinaltable ( f , nofreplacements , ushort )
1236 local coverage = readcoverage ( f , tableoffset + coverage )
1237 for index , newindex in next , coverage do
1238 newindex = newindex + 1
1239 if index > nofglyphs or newindex > nofglyphs then
1240 report ( " invalid index in %s format %i: %i -> %i (max %i) " , " single " , subtype , index , newindex , nofglyphs )
1241 coverage [ index ] = nil
1242 else
1243 coverage [ index ] = replacements [ newindex ]
1244 end
1245 end
1246 return {
1247 coverage = coverage
1248 }
1249 else
1250 report ( " unsupported subtype %a in %a substitution " , subtype , " single " )
1251 end
1252end
1253
1254
1255
1256local function sethandler ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , what )
1257 local tableoffset = lookupoffset + offset
1258 setposition ( f , tableoffset )
1259 local subtype = readushort ( f )
1260 if subtype = = 1 then
1261 local coverage = readushort ( f )
1262 local nofsequence = readushort ( f )
1263 local sequences = readcardinaltable ( f , nofsequence , ushort )
1264 for i = 1 , nofsequence do
1265 setposition ( f , tableoffset + sequences [ i ] )
1266 sequences [ i ] = readcardinaltable ( f , readushort ( f ) , ushort )
1267 end
1268 local coverage = readcoverage ( f , tableoffset + coverage )
1269 for index , newindex in next , coverage do
1270 newindex = newindex + 1
1271 if index > nofglyphs or newindex > nofglyphs then
1272 report ( " invalid index in %s format %i: %i -> %i (max %i) " , what , subtype , index , newindex , nofglyphs )
1273 coverage [ index ] = nil
1274 else
1275 coverage [ index ] = sequences [ newindex ]
1276 end
1277 end
1278 return {
1279 coverage = coverage
1280 }
1281 else
1282 report ( " unsupported subtype %a in %a substitution " , subtype , what )
1283 end
1284end
1285
1286function gsubhandlers . multiple ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1287 return sethandler ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , " multiple " )
1288end
1289
1290function gsubhandlers . alternate ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1291 return sethandler ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , " alternate " )
1292end
1293
1294function gsubhandlers . ligature ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1295 local tableoffset = lookupoffset + offset
1296 setposition ( f , tableoffset )
1297 local subtype = readushort ( f )
1298 if subtype = = 1 then
1299 local coverage = readushort ( f )
1300 local nofsets = readushort ( f )
1301 local ligatures = readcardinaltable ( f , nofsets , ushort )
1302 for i = 1 , nofsets do
1303 local offset = lookupoffset + offset + ligatures [ i ]
1304 setposition ( f , offset )
1305 local n = readushort ( f )
1306 if n = = 1 then
1307 ligatures [ i ] = { offset + readushort ( f ) }
1308 else
1309 local l = { }
1310 for i = 1 , n do
1311 l [ i ] = offset + readushort ( f )
1312 end
1313 ligatures [ i ] = l
1314 end
1315 end
1316 local coverage = readcoverage ( f , tableoffset + coverage )
1317 for index , newindex in next , coverage do
1318 local hash = { }
1319 local ligatures = ligatures [ newindex + 1 ]
1320 for i = 1 , # ligatures do
1321 local offset = ligatures [ i ]
1322 setposition ( f , offset )
1323 local lig = readushort ( f )
1324 local cnt = readushort ( f )
1325 local hsh = hash
1326 for i = 2 , cnt do
1327 local c = readushort ( f )
1328 local h = hsh [ c ]
1329 if not h then
1330 h = { }
1331 hsh [ c ] = h
1332 end
1333 hsh = h
1334 end
1335 hsh . ligature = lig
1336 end
1337 coverage [ index ] = hash
1338 end
1339 return {
1340 coverage = coverage
1341 }
1342 else
1343 report ( " unsupported subtype %a in %a substitution " , subtype , " ligature " )
1344 end
1345end
1346
1347function gsubhandlers . context ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1348 return unchainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , " substitution " ) , " context "
1349end
1350
1351function gsubhandlers . chainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1352 return chainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , " substitution " ) , " chainedcontext "
1353end
1354
1355function gsubhandlers . extension ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1356 return extension ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , gsubtypes , gsubhandlers , " substitution " )
1357end
1358
1359function gsubhandlers . reversechainedcontextsingle ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1360 local tableoffset = lookupoffset + offset
1361 setposition ( f , tableoffset )
1362 local subtype = readushort ( f )
1363 if subtype = = 1 then
1364 local current = readfirst ( f )
1365 local before = readarray ( f )
1366 local after = readarray ( f )
1367 local replacements = readarray ( f )
1368 current = readcoveragearray ( f , tableoffset , current , true )
1369 before = readcoveragearray ( f , tableoffset , before , true )
1370 after = readcoveragearray ( f , tableoffset , after , true )
1371 return {
1372 format = " reversecoverage " ,
1373 rules = {
1374 {
1375 before = before ,
1376 current = current ,
1377 after = after ,
1378 replacements = replacements ,
1379 }
1380 }
1381 } , " reversechainedcontextsingle "
1382 else
1383 report ( " unsupported subtype %a in %a substitution " , subtype , " reversechainedcontextsingle " )
1384 end
1385end
1386
1387
1388
1389local function readpairsets ( f , tableoffset , sets , format1 , format2 , mainoffset , getdelta )
1390 local done = { }
1391 for i = 1 , # sets do
1392 local offset = sets [ i ]
1393 local reused = done [ offset ]
1394 if not reused then
1395 offset = tableoffset + offset
1396 setposition ( f , offset )
1397 local n = readushort ( f )
1398 reused = { }
1399 for i = 1 , n do
1400 reused [ i ] = {
1401 readushort ( f ) ,
1402 readposition ( f , format1 , offset , getdelta ) ,
1403 readposition ( f , format2 , offset , getdelta ) ,
1404 }
1405 end
1406 done [ offset ] = reused
1407 end
1408 sets [ i ] = reused
1409 end
1410 return sets
1411end
1412
1413local function readpairclasssets ( f , nofclasses1 , nofclasses2 , format1 , format2 , mainoffset , getdelta )
1414 local classlist1 = { }
1415 for i = 1 , nofclasses1 do
1416 local classlist2 = { }
1417 classlist1 [ i ] = classlist2
1418 for j = 1 , nofclasses2 do
1419 local one = readposition ( f , format1 , mainoffset , getdelta )
1420 local two = readposition ( f , format2 , mainoffset , getdelta )
1421 if one or two then
1422 classlist2 [ j ] = { one , two }
1423 else
1424 classlist2 [ j ] = false
1425 end
1426 end
1427 end
1428 return classlist1
1429end
1430
1431
1432
1433function gposhandlers . single ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1434 local tableoffset = lookupoffset + offset
1435 setposition ( f , tableoffset )
1436 local subtype = readushort ( f )
1437 local getdelta = fontdata . temporary . getdelta
1438 if subtype = = 1 then
1439 local coverage = readushort ( f )
1440 local format = readushort ( f )
1441 local value = readposition ( f , format , tableoffset , getdelta )
1442 local coverage = readcoverage ( f , tableoffset + coverage )
1443 for index , newindex in next , coverage do
1444 coverage [ index ] = value
1445 end
1446 return {
1447 format = " single " ,
1448 coverage = coverage ,
1449 }
1450 elseif subtype = = 2 then
1451 local coverage = readushort ( f )
1452 local format = readushort ( f )
1453 local nofvalues = readushort ( f )
1454 local values = { }
1455 for i = 1 , nofvalues do
1456 values [ i ] = readposition ( f , format , tableoffset , getdelta )
1457 end
1458 local coverage = readcoverage ( f , tableoffset + coverage )
1459 for index , newindex in next , coverage do
1460 coverage [ index ] = values [ newindex + 1 ]
1461 end
1462 return {
1463 format = " single " ,
1464 coverage = coverage ,
1465 }
1466 else
1467 report ( " unsupported subtype %a in %a positioning " , subtype , " single " )
1468 end
1469end
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593function gposhandlers . pair ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1594 local tableoffset = lookupoffset + offset
1595 setposition ( f , tableoffset )
1596 local subtype = readushort ( f )
1597 local getdelta = fontdata . temporary . getdelta
1598 if subtype = = 1 then
1599 local coverage = readushort ( f )
1600 local format1 = readushort ( f )
1601 local format2 = readushort ( f )
1602 local sets = readarray ( f )
1603 sets = readpairsets ( f , tableoffset , sets , format1 , format2 , mainoffset , getdelta )
1604 coverage = readcoverage ( f , tableoffset + coverage )
1605 local shared = { }
1606 for index , newindex in next , coverage do
1607 local set = sets [ newindex + 1 ]
1608 local hash = { }
1609 for i = 1 , # set do
1610 local value = set [ i ]
1611 if value then
1612 local other = value [ 1 ]
1613 local share = shared [ value ]
1614 if share = = nil then
1615 local first = value [ 2 ]
1616 local second = value [ 3 ]
1617 if first or second then
1618 share = { first , second or nil }
1619 else
1620 share = false
1621 end
1622 shared [ value ] = share
1623 end
1624 hash [ other ] = share or nil
1625 end
1626 end
1627 coverage [ index ] = hash
1628 end
1629 return {
1630 shared = shared and true or nil ,
1631 format = " pair " ,
1632 coverage = coverage ,
1633 }
1634 elseif subtype = = 2 then
1635 local coverage = readushort ( f )
1636 local format1 = readushort ( f )
1637 local format2 = readushort ( f )
1638 local classdef1 = readushort ( f )
1639 local classdef2 = readushort ( f )
1640 local nofclasses1 = readushort ( f )
1641 local nofclasses2 = readushort ( f )
1642 local classlist = readpairclasssets ( f , nofclasses1 , nofclasses2 , format1 , format2 , tableoffset , getdelta )
1643 coverage = readcoverage ( f , tableoffset + coverage )
1644 classdef1 = readclassdef ( f , tableoffset + classdef1 , coverage )
1645 classdef2 = readclassdef ( f , tableoffset + classdef2 , nofglyphs )
1646 local usedcoverage = { }
1647 local shared = { }
1648 for g1 , c1 in next , classdef1 do
1649 if coverage [ g1 ] then
1650 local l1 = classlist [ c1 ]
1651 if l1 then
1652 local hash = { }
1653 for paired , class in next , classdef2 do
1654 local offsets = l1 [ class ]
1655 if offsets then
1656 local first = offsets [ 1 ]
1657 local second = offsets [ 2 ]
1658 if first or second then
1659 local s1 = shared [ first ]
1660 if s1 = = nil then
1661 s1 = { }
1662 shared [ first ] = s1
1663 end
1664 local s2 = s1 [ second ]
1665 if s2 = = nil then
1666 s2 = { first , second or nil }
1667 s1 [ second ] = s2
1668 end
1669 hash [ paired ] = s2
1670 end
1671 end
1672 end
1673 usedcoverage [ g1 ] = hash
1674 end
1675 end
1676 end
1677 return {
1678 shared = shared and true or nil ,
1679 format = " pair " ,
1680 coverage = usedcoverage ,
1681 }
1682 elseif subtype = = 3 then
1683 report ( " yet unsupported subtype %a in %a positioning " , subtype , " pair " )
1684 else
1685 report ( " unsupported subtype %a in %a positioning " , subtype , " pair " )
1686 end
1687end
1688
1689function gposhandlers . cursive ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1690 local tableoffset = lookupoffset + offset
1691 setposition ( f , tableoffset )
1692 local subtype = readushort ( f )
1693 local getdelta = fontdata . temporary . getdelta
1694 if subtype = = 1 then
1695 local coverage = tableoffset + readushort ( f )
1696 local nofrecords = readushort ( f )
1697 local records = { }
1698 for i = 1 , nofrecords do
1699 local entry = readushort ( f )
1700 local exit = readushort ( f )
1701 records [ i ] = {
1702
1703
1704 entry ~ = 0 and ( tableoffset + entry ) or false ,
1705 exit ~ = 0 and ( tableoffset + exit ) or nil ,
1706 }
1707 end
1708
1709
1710 local cc = ( fontdata . temporary . cursivecount or 0 ) + 1
1711 fontdata . temporary . cursivecount = cc
1712 cc = " cc- " . . cc
1713 coverage = readcoverage ( f , coverage )
1714 for i = 1 , nofrecords do
1715 local r = records [ i ]
1716 records [ i ] = {
1717
1718 cc ,
1719
1720
1721 readanchor ( f , r [ 1 ] , getdelta ) or false ,
1722 readanchor ( f , r [ 2 ] , getdelta ) or nil ,
1723 }
1724 end
1725 for index , newindex in next , coverage do
1726 coverage [ index ] = records [ newindex + 1 ]
1727 end
1728 return {
1729 coverage = coverage ,
1730 }
1731 else
1732 report ( " unsupported subtype %a in %a positioning " , subtype , " cursive " )
1733 end
1734end
1735
1736local function handlemark ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , ligature )
1737 local tableoffset = lookupoffset + offset
1738 setposition ( f , tableoffset )
1739 local subtype = readushort ( f )
1740 local getdelta = fontdata . temporary . getdelta
1741 if subtype = = 1 then
1742
1743 local markcoverage = tableoffset + readushort ( f )
1744 local basecoverage = tableoffset + readushort ( f )
1745 local nofclasses = readushort ( f )
1746 local markoffset = tableoffset + readushort ( f )
1747 local baseoffset = tableoffset + readushort ( f )
1748
1749 local markcoverage = readcoverage ( f , markcoverage )
1750 local basecoverage = readcoverage ( f , basecoverage , true )
1751
1752 setposition ( f , markoffset )
1753 local markclasses = { }
1754 local nofmarkclasses = readushort ( f )
1755
1756 local lastanchor = fontdata . lastanchor or 0
1757 local usedanchors = { }
1758
1759 for i = 1 , nofmarkclasses do
1760 local class = readushort ( f ) + 1
1761 local offset = readushort ( f )
1762 if offset = = 0 then
1763 markclasses [ i ] = false
1764 else
1765 markclasses [ i ] = { class , markoffset + offset }
1766 end
1767 usedanchors [ class ] = true
1768 end
1769 for i = 1 , nofmarkclasses do
1770 local mc = markclasses [ i ]
1771 if mc then
1772 mc [ 2 ] = readanchor ( f , mc [ 2 ] , getdelta )
1773 end
1774 end
1775
1776 setposition ( f , baseoffset )
1777 local nofbaserecords = readushort ( f )
1778 local baserecords = { }
1779
1780 if ligature then
1781
1782
1783
1784
1785 for i = 1 , nofbaserecords do
1786 local offset = readushort ( f )
1787 if offset = = 0 then
1788 baserecords [ i ] = false
1789 else
1790 baserecords [ i ] = baseoffset + offset
1791 end
1792 end
1793 for i = 1 , nofbaserecords do
1794 local recordoffset = baserecords [ i ]
1795 if recordoffset then
1796 setposition ( f , recordoffset )
1797 local nofcomponents = readushort ( f )
1798 local components = { }
1799 for i = 1 , nofcomponents do
1800 local classes = { }
1801 for i = 1 , nofclasses do
1802 local offset = readushort ( f )
1803 if offset ~ = 0 then
1804 classes [ i ] = recordoffset + offset
1805 else
1806 classes [ i ] = false
1807 end
1808 end
1809 components [ i ] = classes
1810 end
1811 baserecords [ i ] = components
1812 end
1813 end
1814 local baseclasses = { }
1815 for i = 1 , nofclasses do
1816 baseclasses [ i ] = { }
1817 end
1818 for i = 1 , nofbaserecords do
1819 local components = baserecords [ i ]
1820 if components then
1821 local b = basecoverage [ i ]
1822 for c = 1 , # components do
1823 local classes = components [ c ]
1824 if classes then
1825 for i = 1 , nofclasses do
1826 local anchor = readanchor ( f , classes [ i ] , getdelta )
1827 local bclass = baseclasses [ i ]
1828 local bentry = bclass [ b ]
1829 if bentry then
1830 bentry [ c ] = anchor
1831 else
1832 bclass [ b ] = { [ c ] = anchor }
1833 end
1834 end
1835 end
1836 end
1837 end
1838 end
1839 for index , newindex in next , markcoverage do
1840 markcoverage [ index ] = markclasses [ newindex + 1 ] or nil
1841 end
1842 return {
1843 format = " ligature " ,
1844 baseclasses = baseclasses ,
1845 coverage = markcoverage ,
1846 }
1847 else
1848 for i = 1 , nofbaserecords do
1849 local r = { }
1850 for j = 1 , nofclasses do
1851 local offset = readushort ( f )
1852 if offset = = 0 then
1853 r [ j ] = false
1854 else
1855 r [ j ] = baseoffset + offset
1856 end
1857 end
1858 baserecords [ i ] = r
1859 end
1860 local baseclasses = { }
1861 for i = 1 , nofclasses do
1862 baseclasses [ i ] = { }
1863 end
1864 for i = 1 , nofbaserecords do
1865 local r = baserecords [ i ]
1866 local b = basecoverage [ i ]
1867 for j = 1 , nofclasses do
1868 baseclasses [ j ] [ b ] = readanchor ( f , r [ j ] , getdelta )
1869 end
1870 end
1871 for index , newindex in next , markcoverage do
1872 markcoverage [ index ] = markclasses [ newindex + 1 ] or nil
1873 end
1874
1875 return {
1876 format = " base " ,
1877 baseclasses = baseclasses ,
1878 coverage = markcoverage ,
1879 }
1880 end
1881 else
1882 report ( " unsupported subtype %a in " , subtype )
1883 end
1884
1885end
1886
1887function gposhandlers . marktobase ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1888 return handlemark ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1889end
1890
1891function gposhandlers . marktoligature ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1892 return handlemark ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , true )
1893end
1894
1895function gposhandlers . marktomark ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1896 return handlemark ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1897end
1898
1899function gposhandlers . context ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1900 return unchainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , " positioning " ) , " context "
1901end
1902
1903function gposhandlers . chainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1904 return chainedcontext ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , " positioning " ) , " chainedcontext "
1905end
1906
1907function gposhandlers . extension ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs )
1908 return extension ( f , fontdata , lookupid , lookupoffset , offset , glyphs , nofglyphs , gpostypes , gposhandlers , " positioning " )
1909end
1910
1911
1912
1913do
1914
1915 local plugins = { }
1916
1917 function plugins . size ( f , fontdata , tableoffset , feature )
1918 if fontdata . designsize then
1919
1920
1921 else
1922 local function check ( offset )
1923 setposition ( f , offset )
1924 local designsize = readushort ( f )
1925 if designsize > 0 then
1926 local fontstyleid = readushort ( f )
1927 local guimenuid = readushort ( f )
1928 local minsize = readushort ( f )
1929 local maxsize = readushort ( f )
1930 if minsize = = 0 and maxsize = = 0 and fontstyleid = = 0 and guimenuid = = 0 then
1931 minsize = designsize
1932 maxsize = designsize
1933 end
1934 if designsize > = minsize and designsize < = maxsize then
1935 return minsize , maxsize , designsize
1936 end
1937 end
1938 end
1939 local minsize , maxsize , designsize = check ( tableoffset + feature . offset + feature . parameters )
1940 if not designsize then
1941
1942
1943
1944 minsize , maxsize , designsize = check ( tableoffset + feature . parameters )
1945 if designsize then
1946 report ( " bad size feature in %a, falling back to wrong offset " , fontdata . filename or " ? " )
1947 else
1948 report ( " bad size feature in %a, " , fontdata . filename or " ? " )
1949 end
1950 end
1951 if designsize then
1952 fontdata . minsize = minsize
1953 fontdata . maxsize = maxsize
1954 fontdata . designsize = designsize
1955 end
1956 end
1957 end
1958
1959
1960
1961
1962
1963
1964
1965
1966 local function reorderfeatures ( fontdata , scripts , features )
1967 local scriptlangs = { }
1968 local featurehash = { }
1969 local featureorder = { }
1970 for script , languages in next , scripts do
1971 for language , record in next , languages do
1972 local hash = { }
1973 local list = record . featureindices
1974 for k = 1 , # list do
1975 local index = list [ k ]
1976 local feature = features [ index ]
1977 local lookups = feature . lookups
1978 local tag = feature . tag
1979 if tag then
1980 hash [ tag ] = true
1981 end
1982 if lookups then
1983 for i = 1 , # lookups do
1984 local lookup = lookups [ i ]
1985 local o = featureorder [ lookup ]
1986 if o then
1987 local okay = true
1988 for i = 1 , # o do
1989 if o [ i ] = = tag then
1990 okay = false
1991 break
1992 end
1993 end
1994 if okay then
1995 o [ # o + 1 ] = tag
1996 end
1997 else
1998 featureorder [ lookup ] = { tag }
1999 end
2000 local f = featurehash [ lookup ]
2001 if f then
2002 local h = f [ tag ]
2003 if h then
2004 local s = h [ script ]
2005 if s then
2006 s [ language ] = true
2007 else
2008 h [ script ] = { [ language ] = true }
2009 end
2010 else
2011 f [ tag ] = { [ script ] = { [ language ] = true } }
2012 end
2013 else
2014 featurehash [ lookup ] = { [ tag ] = { [ script ] = { [ language ] = true } } }
2015 end
2016
2017 local h = scriptlangs [ tag ]
2018 if h then
2019 local s = h [ script ]
2020 if s then
2021 s [ language ] = true
2022 else
2023 h [ script ] = { [ language ] = true }
2024 end
2025 else
2026 scriptlangs [ tag ] = { [ script ] = { [ language ] = true } }
2027 end
2028 end
2029 end
2030 end
2031 end
2032 end
2033 return scriptlangs , featurehash , featureorder
2034 end
2035
2036 local function readscriplan ( f , fontdata , scriptoffset )
2037 setposition ( f , scriptoffset )
2038 local nofscripts = readushort ( f )
2039 local scripts = { }
2040 for i = 1 , nofscripts do
2041 scripts [ readtag ( f ) ] = scriptoffset + readushort ( f )
2042 end
2043
2044 local languagesystems = setmetatableindex ( " table " )
2045 for script , offset in next , scripts do
2046 setposition ( f , offset )
2047 local defaultoffset = readushort ( f )
2048 local noflanguages = readushort ( f )
2049 local languages = { }
2050 if defaultoffset > 0 then
2051 languages . dflt = languagesystems [ offset + defaultoffset ]
2052 end
2053 for i = 1 , noflanguages do
2054 local language = readtag ( f )
2055 local offset = offset + readushort ( f )
2056 languages [ language ] = languagesystems [ offset ]
2057 end
2058 scripts [ script ] = languages
2059 end
2060
2061 for offset , usedfeatures in next , languagesystems do
2062 if offset > 0 then
2063 setposition ( f , offset )
2064 local featureindices = { }
2065 usedfeatures . featureindices = featureindices
2066 usedfeatures . lookuporder = readushort ( f )
2067 usedfeatures . requiredindex = readushort ( f )
2068 local noffeatures = readushort ( f )
2069 for i = 1 , noffeatures do
2070 featureindices [ i ] = readushort ( f ) + 1
2071 end
2072 end
2073 end
2074 return scripts
2075 end
2076
2077 local function readfeatures ( f , fontdata , featureoffset )
2078 setposition ( f , featureoffset )
2079 local features = { }
2080 local noffeatures = readushort ( f )
2081 for i = 1 , noffeatures do
2082
2083 features [ i ] = {
2084 tag = readtag ( f ) ,
2085 offset = readushort ( f )
2086 }
2087 end
2088
2089 for i = 1 , noffeatures do
2090 local feature = features [ i ]
2091 local offset = featureoffset + feature . offset
2092 setposition ( f , offset )
2093 local parameters = readushort ( f )
2094 local noflookups = readushort ( f )
2095 if noflookups > 0 then
2096
2097
2098
2099
2100
2101 local lookups = readcardinaltable ( f , noflookups , ushort )
2102 feature . lookups = lookups
2103 for j = 1 , noflookups do
2104 lookups [ j ] = lookups [ j ] + 1
2105 end
2106 end
2107 if parameters > 0 then
2108 feature . parameters = parameters
2109 local plugin = plugins [ feature . tag ]
2110 if plugin then
2111 plugin ( f , fontdata , featureoffset , feature )
2112 end
2113 end
2114 end
2115 return features
2116 end
2117
2118 local function readlookups ( f , lookupoffset , lookuptypes , featurehash , featureorder )
2119 setposition ( f , lookupoffset )
2120 local noflookups = readushort ( f )
2121 local lookups = readcardinaltable ( f , noflookups , ushort )
2122 for lookupid = 1 , noflookups do
2123 local offset = lookups [ lookupid ]
2124 setposition ( f , lookupoffset + offset )
2125 local subtables = { }
2126 local typebits = readushort ( f )
2127 local flagbits = readushort ( f )
2128 local lookuptype = lookuptypes [ typebits ]
2129 local lookupflags = lookupflags [ flagbits ]
2130 local nofsubtables = readushort ( f )
2131 for j = 1 , nofsubtables do
2132 subtables [ j ] = offset + readushort ( f )
2133 end
2134
2135 local markclass = band ( flagbits , 0x0010 ) ~ = 0
2136 if markclass then
2137 markclass = readushort ( f )
2138 end
2139 local markset = rshift ( flagbits , 8 )
2140 if markset > 0 then
2141 markclass = markset
2142 end
2143 lookups [ lookupid ] = {
2144 type = lookuptype ,
2145
2146 flags = lookupflags ,
2147 name = lookupid ,
2148 subtables = subtables ,
2149 markclass = markclass ,
2150 features = featurehash [ lookupid ] ,
2151 order = featureorder [ lookupid ] ,
2152 }
2153 end
2154 return lookups
2155 end
2156
2157 local f_lookupname = formatters [ " %s_%s_%s " ]
2158
2159 local function resolvelookups ( f , lookupoffset , fontdata , lookups , lookuptypes , lookuphandlers , what , tableoffset )
2160
2161 local sequences = fontdata . sequences or { }
2162 local sublookuplist = fontdata . sublookups or { }
2163 fontdata . sequences = sequences
2164 fontdata . sublookups = sublookuplist
2165 local nofsublookups = # sublookuplist
2166 local nofsequences = # sequences
2167 local lastsublookup = nofsublookups
2168 local lastsequence = nofsequences
2169 local lookupnames = lookupnames [ what ]
2170 local sublookuphash = { }
2171 local sublookupcheck = { }
2172 local glyphs = fontdata . glyphs
2173 local nofglyphs = fontdata . nofglyphs or # glyphs
2174 local noflookups = # lookups
2175 local lookupprefix = sub ( what , 2 , 2 )
2176
2177 local usedlookups = false
2178
2179 for lookupid = 1 , noflookups do
2180 local lookup = lookups [ lookupid ]
2181 local lookuptype = lookup . type
2182 local subtables = lookup . subtables
2183 local features = lookup . features
2184 local handler = lookuphandlers [ lookuptype ]
2185 if handler then
2186 local nofsubtables = # subtables
2187 local order = lookup . order
2188 local flags = lookup . flags
2189
2190 if flags [ 1 ] then flags [ 1 ] = " mark " end
2191 if flags [ 2 ] then flags [ 2 ] = " ligature " end
2192 if flags [ 3 ] then flags [ 3 ] = " base " end
2193
2194 local markclass = lookup . markclass
2195
2196 if nofsubtables > 0 then
2197 local steps = { }
2198 local nofsteps = 0
2199 local oldtype = nil
2200 for s = 1 , nofsubtables do
2201 local step , lt = handler ( f , fontdata , lookupid , lookupoffset , subtables [ s ] , glyphs , nofglyphs )
2202 if lt then
2203 lookuptype = lt
2204 if oldtype and lt ~ = oldtype then
2205 report ( " messy %s lookup type %a and %a " , what , lookuptype , oldtype )
2206 end
2207 oldtype = lookuptype
2208 end
2209 if not step then
2210 report ( " unsupported %s lookup type %a " , what , lookuptype )
2211 else
2212 nofsteps = nofsteps + 1
2213 steps [ nofsteps ] = step
2214 local rules = step . rules
2215 if rules then
2216 for i = 1 , # rules do
2217 local rule = rules [ i ]
2218 local before = rule . before
2219 local current = rule . current
2220 local after = rule . after
2221 local replacements = rule . replacements
2222 if before then
2223 for i = 1 , # before do
2224 before [ i ] = tohash ( before [ i ] )
2225 end
2226
2227 rule . before = reversed ( before )
2228 end
2229 if current then
2230 if replacements then
2231
2232
2233 local first = current [ 1 ]
2234 local hash = { }
2235 local repl = { }
2236 for i = 1 , # first do
2237 local c = first [ i ]
2238 hash [ c ] = true
2239 repl [ c ] = replacements [ i ]
2240 end
2241 rule . current = { hash }
2242 rule . replacements = repl
2243 else
2244 for i = 1 , # current do
2245 current [ i ] = tohash ( current [ i ] )
2246 end
2247 end
2248 else
2249
2250 end
2251 if after then
2252 for i = 1 , # after do
2253 after [ i ] = tohash ( after [ i ] )
2254 end
2255 end
2256 if usedlookups then
2257 local lookups = rule . lookups
2258 if lookups then
2259 for k , v in next , lookups do
2260 if v then
2261 for k , v in next , v do
2262 usedlookups [ v ] = usedlookups [ v ] + 1
2263 end
2264 end
2265 end
2266 end
2267 end
2268 end
2269 end
2270 end
2271 end
2272 if nofsteps ~ = nofsubtables then
2273 report ( " bogus subtables removed in %s lookup type %a " , what , lookuptype )
2274 end
2275 lookuptype = lookupnames [ lookuptype ] or lookuptype
2276 if features then
2277 nofsequences = nofsequences + 1
2278
2279 local l = {
2280 index = nofsequences ,
2281 name = f_lookupname ( lookupprefix , " s " , lookupid + lookupidoffset ) ,
2282 steps = steps ,
2283 nofsteps = nofsteps ,
2284 type = lookuptype ,
2285 markclass = markclass or nil ,
2286 flags = flags ,
2287
2288 order = order ,
2289 features = features ,
2290 }
2291 sequences [ nofsequences ] = l
2292 lookup . done = l
2293 else
2294 nofsublookups = nofsublookups + 1
2295
2296 local l = {
2297 index = nofsublookups ,
2298 name = f_lookupname ( lookupprefix , " l " , lookupid + lookupidoffset ) ,
2299 steps = steps ,
2300 nofsteps = nofsteps ,
2301 type = lookuptype ,
2302 markclass = markclass or nil ,
2303 flags = flags ,
2304
2305 }
2306 sublookuplist [ nofsublookups ] = l
2307 sublookuphash [ lookupid ] = nofsublookups
2308 sublookupcheck [ lookupid ] = 0
2309 lookup . done = l
2310 end
2311 else
2312 report ( " no subtables for lookup %a " , lookupid )
2313 end
2314 else
2315 report ( " no handler for lookup %a with type %a " , lookupid , lookuptype )
2316 end
2317 end
2318
2319 if usedlookups then
2320 report ( " used %s lookups: % t " , what , sortedkeys ( usedlookups ) )
2321 end
2322
2323
2324
2325
2326
2327
2328
2329 local reported = { }
2330
2331 local function report_issue ( i , what , sequence , kind )
2332 local name = sequence . name
2333 if not reported [ name ] then
2334 report ( " rule %i in %s lookup %a has %s lookups " , i , what , name , kind )
2335 reported [ name ] = true
2336 end
2337 end
2338
2339 for i = lastsequence + 1 , nofsequences do
2340 local sequence = sequences [ i ]
2341 local steps = sequence . steps
2342 for i = 1 , # steps do
2343 local step = steps [ i ]
2344 local rules = step . rules
2345 if rules then
2346 for i = 1 , # rules do
2347 local rule = rules [ i ]
2348 local rlookups = rule . lookups
2349 if not rlookups then
2350 report_issue ( i , what , sequence , " no " )
2351 elseif not next ( rlookups ) then
2352
2353
2354 rule . lookups = nil
2355 else
2356
2357
2358 local length = # rlookups
2359 for index = 1 , length do
2360 local lookuplist = rlookups [ index ]
2361 if lookuplist then
2362 local length = # lookuplist
2363 local found = { }
2364 local noffound = 0
2365 for index = 1 , length do
2366 local lookupid = lookuplist [ index ]
2367 if lookupid then
2368 local h = sublookuphash [ lookupid ]
2369 if not h then
2370
2371
2372 local lookup = lookups [ lookupid ]
2373 if lookup then
2374 local d = lookup . done
2375 if d then
2376 nofsublookups = nofsublookups + 1
2377
2378 local l = {
2379 index = nofsublookups ,
2380 name = f_lookupname ( lookupprefix , " d " , lookupid + lookupidoffset ) ,
2381 derived = true ,
2382 steps = d . steps ,
2383 nofsteps = d . nofsteps ,
2384 type = d . lookuptype or " gsub_single " ,
2385 markclass = d . markclass or nil ,
2386 flags = d . flags ,
2387
2388 }
2389 sublookuplist [ nofsublookups ] = copy ( l )
2390 sublookuphash [ lookupid ] = nofsublookups
2391 sublookupcheck [ lookupid ] = 1
2392 h = nofsublookups
2393 else
2394 report_issue ( i , what , sequence , " missing " )
2395 rule . lookups = nil
2396 break
2397 end
2398 else
2399 report_issue ( i , what , sequence , " bad " )
2400 rule . lookups = nil
2401 break
2402 end
2403 else
2404 sublookupcheck [ lookupid ] = sublookupcheck [ lookupid ] + 1
2405 end
2406 if h then
2407 noffound = noffound + 1
2408 found [ noffound ] = h
2409 end
2410 end
2411 end
2412 rlookups [ index ] = noffound > 0 and found or false
2413 else
2414 rlookups [ index ] = false
2415 end
2416 end
2417 end
2418 end
2419 end
2420 end
2421 end
2422
2423 for i , n in sortedhash ( sublookupcheck ) do
2424 local l = lookups [ i ]
2425 local t = l . type
2426 if n = = 0 and t ~ = " extension " then
2427 local d = l . done
2428 report ( " %s lookup %s of type %a is not used " , what , d and d . name or l . name , t )
2429 end
2430 end
2431
2432 end
2433
2434 local function loadvariations ( f , fontdata , variationsoffset , lookuptypes , featurehash , featureorder )
2435 setposition ( f , variationsoffset )
2436 local version = readulong ( f )
2437 local nofrecords = readulong ( f )
2438 local records = { }
2439 for i = 1 , nofrecords do
2440 records [ i ] = {
2441 conditions = readulong ( f ) ,
2442 substitutions = readulong ( f ) ,
2443 }
2444 end
2445 for i = 1 , nofrecords do
2446 local record = records [ i ]
2447 local offset = record . conditions
2448 if offset = = 0 then
2449 record . condition = nil
2450 record . matchtype = " always "
2451 else
2452 local offset = variationsoffset + offset
2453 setposition ( f , offset )
2454 local nofconditions = readushort ( f )
2455 local conditions = { }
2456 for i = 1 , nofconditions do
2457 conditions [ i ] = offset + readulong ( f )
2458 end
2459 record . conditions = conditions
2460 record . matchtype = " condition "
2461 end
2462 end
2463 for i = 1 , nofrecords do
2464 local record = records [ i ]
2465 if record . matchtype = = " condition " then
2466 local conditions = record . conditions
2467 for i = 1 , # conditions do
2468 setposition ( f , conditions [ i ] )
2469 conditions [ i ] = {
2470 format = readushort ( f ) ,
2471 axis = readushort ( f ) ,
2472 minvalue = read2dot14 ( f ) ,
2473 maxvalue = read2dot14 ( f ) ,
2474 }
2475 end
2476 end
2477 end
2478
2479 for i = 1 , nofrecords do
2480 local record = records [ i ]
2481 local offset = record . substitutions
2482 if offset = = 0 then
2483 record . substitutions = { }
2484 else
2485 setposition ( f , variationsoffset + offset )
2486 local version = readulong ( f )
2487 local nofsubstitutions = readushort ( f )
2488 local substitutions = { }
2489 for i = 1 , nofsubstitutions do
2490 substitutions [ readushort ( f ) ] = readulong ( f )
2491 end
2492 for index , alternates in sortedhash ( substitutions ) do
2493 if index = = 0 then
2494 record . substitutions = false
2495 else
2496 local tableoffset = variationsoffset + offset + alternates
2497 setposition ( f , tableoffset )
2498 local parameters = readulong ( f )
2499 local noflookups = readushort ( f )
2500 local lookups = readcardinaltable ( f , noflookups , ushort )
2501
2502 record . substitutions = lookups
2503 end
2504 end
2505 end
2506 end
2507 setvariabledata ( fontdata , " features " , records )
2508 end
2509
2510 local function readscripts ( f , fontdata , what , lookuptypes , lookuphandlers , lookupstoo )
2511 local tableoffset = gotodatatable ( f , fontdata , what , true )
2512 if tableoffset then
2513 local version = readulong ( f )
2514 local scriptoffset = tableoffset + readushort ( f )
2515 local featureoffset = tableoffset + readushort ( f )
2516 local lookupoffset = tableoffset + readushort ( f )
2517 local variationsoffset = version > 0x00010000 and ( tableoffset + readulong ( f ) ) or 0
2518 if not scriptoffset then
2519 return
2520 end
2521 local scripts = readscriplan ( f , fontdata , scriptoffset )
2522 local features = readfeatures ( f , fontdata , featureoffset )
2523
2524 local scriptlangs , featurehash , featureorder = reorderfeatures ( fontdata , scripts , features )
2525
2526 if fontdata . features then
2527 fontdata . features [ what ] = scriptlangs
2528 else
2529 fontdata . features = { [ what ] = scriptlangs }
2530 end
2531
2532 if not lookupstoo then
2533 return
2534 end
2535
2536 local lookups = readlookups ( f , lookupoffset , lookuptypes , featurehash , featureorder )
2537
2538 if lookups then
2539 resolvelookups ( f , lookupoffset , fontdata , lookups , lookuptypes , lookuphandlers , what , tableoffset )
2540 end
2541
2542 if variationsoffset > 0 then
2543 loadvariations ( f , fontdata , variationsoffset , lookuptypes , featurehash , featureorder )
2544 end
2545 end
2546 end
2547
2548 local function checkkerns ( f , fontdata , specification )
2549 local datatable = fontdata . tables . kern
2550 if not datatable then
2551 return
2552 end
2553 local features = fontdata . features
2554 local gposfeatures = features and features . gpos
2555 local name
2556 if not gposfeatures or not gposfeatures . kern then
2557 name = " kern "
2558 elseif specification . globalkerns then
2559 name = " globalkern "
2560 else
2561 report ( " ignoring global kern table, using gpos kern feature " )
2562 return
2563 end
2564 setposition ( f , datatable . offset )
2565 local version = readushort ( f )
2566 local noftables = readushort ( f )
2567 if noftables > 1 then
2568 report ( " adding global kern table as gpos feature %a " , name )
2569 local kerns = setmetatableindex ( " table " )
2570 for i = 1 , noftables do
2571 local version = readushort ( f )
2572 local length = readushort ( f )
2573 local coverage = readushort ( f )
2574
2575 local format = rshift ( coverage , 8 )
2576 if format = = 0 then
2577 local nofpairs = readushort ( f )
2578 local searchrange = readushort ( f )
2579 local entryselector = readushort ( f )
2580 local rangeshift = readushort ( f )
2581 for i = 1 , nofpairs do
2582 kerns [ readushort ( f ) ] [ readushort ( f ) ] = readfword ( f )
2583 end
2584 elseif format = = 2 then
2585
2586 else
2587
2588 end
2589 end
2590 local feature = { dflt = { dflt = true } }
2591 if not features then
2592 fontdata . features = { gpos = { [ name ] = feature } }
2593 elseif not gposfeatures then
2594 fontdata . features . gpos = { [ name ] = feature }
2595 else
2596 gposfeatures [ name ] = feature
2597 end
2598 local sequences = fontdata . sequences
2599 if not sequences then
2600 sequences = { }
2601 fontdata . sequences = sequences
2602 end
2603 local nofsequences = # sequences + 1
2604 sequences [ nofsequences ] = {
2605 index = nofsequences ,
2606 name = name ,
2607 steps = {
2608 {
2609 coverage = kerns ,
2610 format = " kern " ,
2611 } ,
2612 } ,
2613 nofsteps = 1 ,
2614 type = " gpos_pair " ,
2615 flags = { false , false , false , false } ,
2616 order = { name } ,
2617 features = { [ name ] = feature } ,
2618 }
2619 else
2620 report ( " ignoring empty kern table of feature %a " , name )
2621 end
2622 end
2623
2624 function readers . gsub ( f , fontdata , specification )
2625 if specification . details then
2626 readscripts ( f , fontdata , " gsub " , gsubtypes , gsubhandlers , specification . lookups )
2627 end
2628 end
2629
2630 function readers . gpos ( f , fontdata , specification )
2631 if specification . details then
2632 readscripts ( f , fontdata , " gpos " , gpostypes , gposhandlers , specification . lookups )
2633 if specification . lookups then
2634 checkkerns ( f , fontdata , specification )
2635 end
2636 end
2637 end
2638
2639end
2640
2641function readers . gdef ( f , fontdata , specification )
2642 if not specification . glyphs then
2643 return
2644 end
2645 local datatable = fontdata . tables . gdef
2646 if datatable then
2647 local tableoffset = datatable . offset
2648 setposition ( f , tableoffset )
2649 local version = readulong ( f )
2650 local classoffset = readushort ( f )
2651 local attachmentoffset = readushort ( f )
2652 local ligaturecarets = readushort ( f )
2653 local markclassoffset = readushort ( f )
2654 local marksetsoffset = version > = 0x00010002 and readushort ( f ) or 0
2655 local varsetsoffset = version > = 0x00010003 and readulong ( f ) or 0
2656 local glyphs = fontdata . glyphs
2657 local marks = { }
2658 local markclasses = setmetatableindex ( " table " )
2659 local marksets = setmetatableindex ( " table " )
2660 fontdata . marks = marks
2661 fontdata . markclasses = markclasses
2662 fontdata . marksets = marksets
2663
2664 if classoffset ~ = 0 then
2665 setposition ( f , tableoffset + classoffset )
2666 local classformat = readushort ( f )
2667 if classformat = = 1 then
2668 local firstindex = readushort ( f )
2669 local lastindex = firstindex + readushort ( f ) - 1
2670 for index = firstindex , lastindex do
2671 local class = classes [ readushort ( f ) ]
2672 if class = = " mark " then
2673 marks [ index ] = true
2674 end
2675 glyphs [ index ] . class = class
2676 end
2677 elseif classformat = = 2 then
2678 local nofranges = readushort ( f )
2679 for i = 1 , nofranges do
2680 local firstindex = readushort ( f )
2681 local lastindex = readushort ( f )
2682 local class = classes [ readushort ( f ) ]
2683 if class then
2684 for index = firstindex , lastindex do
2685 glyphs [ index ] . class = class
2686 if class = = " mark " then
2687 marks [ index ] = true
2688 end
2689 end
2690 end
2691 end
2692 end
2693 end
2694
2695 if markclassoffset ~ = 0 then
2696 setposition ( f , tableoffset + markclassoffset )
2697 local classformat = readushort ( f )
2698 if classformat = = 1 then
2699 local firstindex = readushort ( f )
2700 local lastindex = firstindex + readushort ( f ) - 1
2701 for index = firstindex , lastindex do
2702 markclasses [ readushort ( f ) ] [ index ] = true
2703 end
2704 elseif classformat = = 2 then
2705 local nofranges = readushort ( f )
2706 for i = 1 , nofranges do
2707 local firstindex = readushort ( f )
2708 local lastindex = readushort ( f )
2709 local class = markclasses [ readushort ( f ) ]
2710 for index = firstindex , lastindex do
2711 class [ index ] = true
2712 end
2713 end
2714 end
2715 end
2716
2717 if marksetsoffset ~ = 0 then
2718 marksetsoffset = tableoffset + marksetsoffset
2719 setposition ( f , marksetsoffset )
2720 local format = readushort ( f )
2721 if format = = 1 then
2722 local nofsets = readushort ( f )
2723 local sets = readcardinaltable ( f , nofsets , ulong )
2724 for i = 1 , nofsets do
2725 local offset = sets [ i ]
2726 if offset ~ = 0 then
2727 marksets [ i ] = readcoverage ( f , marksetsoffset + offset )
2728 end
2729 end
2730 end
2731 end
2732
2733 local factors = specification . factors
2734
2735 if ( specification . variable or factors ) and varsetsoffset ~ = 0 then
2736
2737 local regions , deltas = readvariationdata ( f , tableoffset + varsetsoffset , factors )
2738
2739
2740
2741 if factors then
2742 fontdata . temporary . getdelta = function ( outer , inner )
2743 local delta = deltas [ outer + 1 ]
2744 if delta then
2745 local d = delta . deltas [ inner + 1 ]
2746 if d then
2747 local scales = delta . scales
2748 local dd = 0
2749 for i = 1 , # scales do
2750 local di = d [ i ]
2751 if di then
2752 dd = dd + scales [ i ] * di
2753 else
2754 break
2755 end
2756 end
2757 return round ( dd )
2758 end
2759 end
2760 return 0
2761 end
2762 end
2763
2764 end
2765 end
2766end
2767
2768
2769
2770
2771local function readmathvalue ( f )
2772 local v = readshort ( f )
2773 skipshort ( f , 1 )
2774 return v
2775end
2776
2777local function readmathconstants ( f , fontdata , offset )
2778 setposition ( f , offset )
2779 fontdata . mathconstants = {
2780 ScriptPercentScaleDown = readshort ( f ) ,
2781 ScriptScriptPercentScaleDown = readshort ( f ) ,
2782 DelimitedSubFormulaMinHeight = readushort ( f ) ,
2783 DisplayOperatorMinHeight = readushort ( f ) ,
2784 MathLeading = readmathvalue ( f ) ,
2785 AxisHeight = readmathvalue ( f ) ,
2786 AccentBaseHeight = readmathvalue ( f ) ,
2787 FlattenedAccentBaseHeight = readmathvalue ( f ) ,
2788 SubscriptShiftDown = readmathvalue ( f ) ,
2789 SubscriptTopMax = readmathvalue ( f ) ,
2790 SubscriptBaselineDropMin = readmathvalue ( f ) ,
2791 SuperscriptShiftUp = readmathvalue ( f ) ,
2792 SuperscriptShiftUpCramped = readmathvalue ( f ) ,
2793 SuperscriptBottomMin = readmathvalue ( f ) ,
2794 SuperscriptBaselineDropMax = readmathvalue ( f ) ,
2795 SubSuperscriptGapMin = readmathvalue ( f ) ,
2796 SuperscriptBottomMaxWithSubscript = readmathvalue ( f ) ,
2797 SpaceAfterScript = readmathvalue ( f ) ,
2798 UpperLimitGapMin = readmathvalue ( f ) ,
2799 UpperLimitBaselineRiseMin = readmathvalue ( f ) ,
2800 LowerLimitGapMin = readmathvalue ( f ) ,
2801 LowerLimitBaselineDropMin = readmathvalue ( f ) ,
2802 StackTopShiftUp = readmathvalue ( f ) ,
2803 StackTopDisplayStyleShiftUp = readmathvalue ( f ) ,
2804 StackBottomShiftDown = readmathvalue ( f ) ,
2805 StackBottomDisplayStyleShiftDown = readmathvalue ( f ) ,
2806 StackGapMin = readmathvalue ( f ) ,
2807 StackDisplayStyleGapMin = readmathvalue ( f ) ,
2808 StretchStackTopShiftUp = readmathvalue ( f ) ,
2809 StretchStackBottomShiftDown = readmathvalue ( f ) ,
2810 StretchStackGapAboveMin = readmathvalue ( f ) ,
2811 StretchStackGapBelowMin = readmathvalue ( f ) ,
2812 FractionNumeratorShiftUp = readmathvalue ( f ) ,
2813 FractionNumeratorDisplayStyleShiftUp = readmathvalue ( f ) ,
2814 FractionDenominatorShiftDown = readmathvalue ( f ) ,
2815 FractionDenominatorDisplayStyleShiftDown = readmathvalue ( f ) ,
2816 FractionNumeratorGapMin = readmathvalue ( f ) ,
2817 FractionNumeratorDisplayStyleGapMin = readmathvalue ( f ) ,
2818 FractionRuleThickness = readmathvalue ( f ) ,
2819 FractionDenominatorGapMin = readmathvalue ( f ) ,
2820 FractionDenominatorDisplayStyleGapMin = readmathvalue ( f ) ,
2821 SkewedFractionHorizontalGap = readmathvalue ( f ) ,
2822 SkewedFractionVerticalGap = readmathvalue ( f ) ,
2823 OverbarVerticalGap = readmathvalue ( f ) ,
2824 OverbarRuleThickness = readmathvalue ( f ) ,
2825 OverbarExtraAscender = readmathvalue ( f ) ,
2826 UnderbarVerticalGap = readmathvalue ( f ) ,
2827 UnderbarRuleThickness = readmathvalue ( f ) ,
2828 UnderbarExtraDescender = readmathvalue ( f ) ,
2829 RadicalVerticalGap = readmathvalue ( f ) ,
2830 RadicalDisplayStyleVerticalGap = readmathvalue ( f ) ,
2831 RadicalRuleThickness = readmathvalue ( f ) ,
2832 RadicalExtraAscender = readmathvalue ( f ) ,
2833 RadicalKernBeforeDegree = readmathvalue ( f ) ,
2834 RadicalKernAfterDegree = readmathvalue ( f ) ,
2835 RadicalDegreeBottomRaisePercent = readshort ( f ) ,
2836 }
2837end
2838
2839local function readmathglyphinfo ( f , fontdata , offset )
2840 setposition ( f , offset )
2841 local italics = readushort ( f )
2842 local accents = readushort ( f )
2843 local extensions = readushort ( f )
2844 local kerns = readushort ( f )
2845 local glyphs = fontdata . glyphs
2846 if italics ~ = 0 then
2847 setposition ( f , offset + italics )
2848 local coverage = readushort ( f )
2849 local nofglyphs = readushort ( f )
2850 coverage = readcoverage ( f , offset + italics + coverage , true )
2851 setposition ( f , offset + italics + 4 )
2852 for i = 1 , nofglyphs do
2853 local italic = readmathvalue ( f )
2854 if italic ~ = 0 then
2855 local glyph = glyphs [ coverage [ i ] ]
2856 local math = glyph . math
2857 if not math then
2858 glyph . math = { italic = italic }
2859 else
2860 math . italic = italic
2861 end
2862 end
2863 end
2864 fontdata . hasitalics = true
2865 end
2866 if accents ~ = 0 then
2867 setposition ( f , offset + accents )
2868 local coverage = readushort ( f )
2869 local nofglyphs = readushort ( f )
2870 coverage = readcoverage ( f , offset + accents + coverage , true )
2871 setposition ( f , offset + accents + 4 )
2872 for i = 1 , nofglyphs do
2873 local accent = readmathvalue ( f )
2874 if accent ~ = 0 then
2875 local glyph = glyphs [ coverage [ i ] ]
2876 local math = glyph . math
2877 if not math then
2878 glyph . math = { accent = accent }
2879 else
2880 math . accent = accent
2881 end
2882 end
2883 end
2884 end
2885 if extensions ~ = 0 then
2886 setposition ( f , offset + extensions )
2887 end
2888 if kerns ~ = 0 then
2889 local kernoffset = offset + kerns
2890 setposition ( f , kernoffset )
2891 local coverage = readushort ( f )
2892 local nofglyphs = readushort ( f )
2893 if nofglyphs > 0 then
2894 local function get ( offset )
2895 setposition ( f , kernoffset + offset )
2896 local n = readushort ( f )
2897 if n = = 0 then
2898 local k = readmathvalue ( f )
2899 if k = = 0 then
2900
2901 else
2902 return { { kern = k } }
2903 end
2904 else
2905 local l = { }
2906 for i = 1 , n do
2907 l [ i ] = { height = readmathvalue ( f ) }
2908 end
2909 for i = 1 , n do
2910 l [ i ] . kern = readmathvalue ( f )
2911 end
2912 l [ n + 1 ] = { kern = readmathvalue ( f ) }
2913 return l
2914 end
2915 end
2916 local kernsets = { }
2917 for i = 1 , nofglyphs do
2918 local topright = readushort ( f )
2919 local topleft = readushort ( f )
2920 local bottomright = readushort ( f )
2921 local bottomleft = readushort ( f )
2922 kernsets [ i ] = {
2923 topright = topright ~ = 0 and topright or nil ,
2924 topleft = topleft ~ = 0 and topleft or nil ,
2925 bottomright = bottomright ~ = 0 and bottomright or nil ,
2926 bottomleft = bottomleft ~ = 0 and bottomleft or nil ,
2927 }
2928 end
2929 coverage = readcoverage ( f , kernoffset + coverage , true )
2930 for i = 1 , nofglyphs do
2931 local kernset = kernsets [ i ]
2932 if next ( kernset ) then
2933 local k = kernset . topright if k then kernset . topright = get ( k ) end
2934 local k = kernset . topleft if k then kernset . topleft = get ( k ) end
2935 local k = kernset . bottomright if k then kernset . bottomright = get ( k ) end
2936 local k = kernset . bottomleft if k then kernset . bottomleft = get ( k ) end
2937 if next ( kernset ) then
2938 local glyph = glyphs [ coverage [ i ] ]
2939 local math = glyph . math
2940 if math then
2941 math . kerns = kernset
2942 else
2943 glyph . math = { kerns = kernset }
2944 end
2945 end
2946 end
2947 end
2948 end
2949 end
2950end
2951
2952local function readmathvariants ( f , fontdata , offset )
2953 setposition ( f , offset )
2954 local glyphs = fontdata . glyphs
2955 local minoverlap = readushort ( f )
2956 local vcoverage = readushort ( f )
2957 local hcoverage = readushort ( f )
2958 local vnofglyphs = readushort ( f )
2959 local hnofglyphs = readushort ( f )
2960 local vconstruction = readcardinaltable ( f , vnofglyphs , ushort )
2961 local hconstruction = readcardinaltable ( f , hnofglyphs , ushort )
2962
2963 fontdata . mathconstants . MinConnectorOverlap = minoverlap
2964
2965
2966
2967
2968
2969
2970 local function get ( offset , coverage , nofglyphs , construction , kvariants , kparts , kitalic )
2971 if coverage ~ = 0 and nofglyphs > 0 then
2972 local coverage = readcoverage ( f , offset + coverage , true )
2973 for i = 1 , nofglyphs do
2974 local c = construction [ i ]
2975 if c ~ = 0 then
2976 local index = coverage [ i ]
2977 local glyph = glyphs [ index ]
2978 local math = glyph . math
2979 setposition ( f , offset + c )
2980 local assembly = readushort ( f )
2981 local nofvariants = readushort ( f )
2982 if nofvariants > 0 then
2983 local variants , v = nil , 0
2984 for i = 1 , nofvariants do
2985 local variant = readushort ( f )
2986 if variant = = index then
2987
2988 elseif variants then
2989 v = v + 1
2990 variants [ v ] = variant
2991 else
2992 v = 1
2993 variants = { variant }
2994 end
2995 skipshort ( f )
2996 end
2997 if not variants then
2998
2999 elseif not math then
3000 math = { [ kvariants ] = variants }
3001 glyph . math = math
3002 else
3003 math [ kvariants ] = variants
3004 end
3005 end
3006 if assembly ~ = 0 then
3007 setposition ( f , offset + c + assembly )
3008 local italic = readmathvalue ( f )
3009 local nofparts = readushort ( f )
3010 local parts = { }
3011 for i = 1 , nofparts do
3012 local p = {
3013 glyph = readushort ( f ) ,
3014 start = readushort ( f ) ,
3015 [ " end " ] = readushort ( f ) ,
3016 advance = readushort ( f ) ,
3017 }
3018 local flags = readushort ( f )
3019 if band ( flags , 0x0001 ) ~ = 0 then
3020 p . extender = 1
3021 end
3022 parts [ i ] = p
3023 end
3024 if not math then
3025 math = {
3026 [ kparts ] = parts
3027 }
3028 glyph . math = math
3029 else
3030 math [ kparts ] = parts
3031 end
3032 if italic and italic ~ = 0 then
3033 math [ kitalic ] = italic
3034 end
3035 end
3036 end
3037 end
3038 end
3039 end
3040
3041 get ( offset , vcoverage , vnofglyphs , vconstruction , " vvariants " , " vparts " , " vitalic " )
3042 get ( offset , hcoverage , hnofglyphs , hconstruction , " hvariants " , " hparts " , " hitalic " )
3043end
3044
3045function readers . math ( f , fontdata , specification )
3046 local tableoffset = gotodatatable ( f , fontdata , " math " , specification . glyphs )
3047 if tableoffset then
3048 local version = readulong ( f )
3049
3050
3051
3052
3053 local constants = readushort ( f )
3054 local glyphinfo = readushort ( f )
3055 local variants = readushort ( f )
3056 if constants = = 0 then
3057 report ( " the math table of %a has no constants " , fontdata . filename )
3058 else
3059 readmathconstants ( f , fontdata , tableoffset + constants )
3060 end
3061 if glyphinfo ~ = 0 then
3062 readmathglyphinfo ( f , fontdata , tableoffset + glyphinfo )
3063 end
3064 if variants ~ = 0 then
3065 readmathvariants ( f , fontdata , tableoffset + variants )
3066 end
3067 end
3068end
3069
3070function readers . colr ( f , fontdata , specification )
3071 local tableoffset = gotodatatable ( f , fontdata , " colr " , specification . glyphs )
3072 if tableoffset then
3073 local version = readushort ( f )
3074 if version ~ = 0 then
3075 report ( " table version %a of %a is not supported (yet), maybe font %s is bad " , version , " colr " , fontdata . filename )
3076 return
3077 end
3078 if not fontdata . tables . cpal then
3079 report ( " color table %a in font %a has no mandate %a table " , " colr " , fontdata . filename , " cpal " )
3080 fontdata . colorpalettes = { }
3081 end
3082 local glyphs = fontdata . glyphs
3083 local nofglyphs = readushort ( f )
3084 local baseoffset = readulong ( f )
3085 local layeroffset = readulong ( f )
3086 local noflayers = readushort ( f )
3087 local layerrecords = { }
3088 local maxclass = 0
3089
3090
3091
3092 setposition ( f , tableoffset + layeroffset )
3093 for i = 1 , noflayers do
3094 local slot = readushort ( f )
3095 local class = readushort ( f )
3096 if class < 0xFFFF then
3097 class = class + 1
3098 if class > maxclass then
3099 maxclass = class
3100 end
3101 end
3102 layerrecords [ i ] = {
3103 slot = slot ,
3104 class = class ,
3105 }
3106 end
3107 fontdata . maxcolorclass = maxclass
3108 setposition ( f , tableoffset + baseoffset )
3109 for i = 0 , nofglyphs -1 do
3110 local glyphindex = readushort ( f )
3111 local firstlayer = readushort ( f )
3112 local noflayers = readushort ( f )
3113 local t = { }
3114 for i = 1 , noflayers do
3115 t [ i ] = layerrecords [ firstlayer + i ]
3116 end
3117 glyphs [ glyphindex ] . colors = t
3118 end
3119 end
3120 fontdata . hascolor = true
3121end
3122
3123function readers . cpal ( f , fontdata , specification )
3124 local tableoffset = gotodatatable ( f , fontdata , " cpal " , specification . glyphs )
3125 if tableoffset then
3126 local version = readushort ( f )
3127
3128
3129
3130
3131 local nofpaletteentries = readushort ( f )
3132 local nofpalettes = readushort ( f )
3133 local nofcolorrecords = readushort ( f )
3134 local firstcoloroffset = readulong ( f )
3135 local colorrecords = { }
3136 local palettes = readcardinaltable ( f , nofpalettes , ushort )
3137 if version = = 1 then
3138
3139 local palettettypesoffset = readulong ( f )
3140 local palettelabelsoffset = readulong ( f )
3141 local paletteentryoffset = readulong ( f )
3142 end
3143 setposition ( f , tableoffset + firstcoloroffset )
3144 for i = 1 , nofcolorrecords do
3145 local b , g , r , a = readbytes ( f , 4 )
3146 colorrecords [ i ] = {
3147 r , g , b , a ~ = 255 and a or nil ,
3148 }
3149 end
3150 for i = 1 , nofpalettes do
3151 local p = { }
3152 local o = palettes [ i ]
3153 for j = 1 , nofpaletteentries do
3154 p [ j ] = colorrecords [ o + j ]
3155 end
3156 palettes [ i ] = p
3157 end
3158 fontdata . colorpalettes = palettes
3159 end
3160end
3161
3162local compress = gzip and gzip . compress
3163local compressed = compress and gzip . compressed
3164
3165
3166
3167
3168
3169
3170function readers . svg ( f , fontdata , specification )
3171 local tableoffset = gotodatatable ( f , fontdata , " svg " , specification . glyphs )
3172 if tableoffset then
3173 local version = readushort ( f )
3174
3175
3176
3177
3178 local glyphs = fontdata . glyphs
3179 local indexoffset = tableoffset + readulong ( f )
3180 local reserved = readulong ( f )
3181 setposition ( f , indexoffset )
3182 local nofentries = readushort ( f )
3183 local entries = { }
3184 for i = 1 , nofentries do
3185 entries [ i ] = {
3186 first = readushort ( f ) ,
3187 last = readushort ( f ) ,
3188 offset = indexoffset + readulong ( f ) ,
3189 length = readulong ( f ) ,
3190 }
3191 end
3192 for i = 1 , nofentries do
3193 local entry = entries [ i ]
3194 setposition ( f , entry . offset )
3195 local data = readstring ( f , entry . length )
3196 if compressed and not compressed ( data ) then
3197 data = compress ( data )
3198 end
3199 entries [ i ] = {
3200 first = entry . first ,
3201 last = entry . last ,
3202 data = data
3203 }
3204 end
3205 fontdata . svgshapes = entries
3206 end
3207 fontdata . hascolor = true
3208end
3209
3210function readers . sbix ( f , fontdata , specification )
3211 local tableoffset = gotodatatable ( f , fontdata , " sbix " , specification . glyphs )
3212 if tableoffset then
3213 local version = readushort ( f )
3214 local flags = readushort ( f )
3215 local nofstrikes = readulong ( f )
3216 local strikes = { }
3217 local nofglyphs = fontdata . nofglyphs
3218 for i = 1 , nofstrikes do
3219 strikes [ i ] = readulong ( f )
3220 end
3221 local shapes = { }
3222 local done = 0
3223 for i = 1 , nofstrikes do
3224 local strikeoffset = strikes [ i ] + tableoffset
3225 setposition ( f , strikeoffset )
3226 strikes [ i ] = {
3227 ppem = readushort ( f ) ,
3228 ppi = readushort ( f ) ,
3229 offset = strikeoffset
3230 }
3231 end
3232
3233 sort ( strikes , function ( a , b )
3234 if b . ppem = = a . ppem then
3235 return b . ppi < a . ppi
3236 else
3237 return b . ppem < a . ppem
3238 end
3239 end )
3240 local glyphs = { }
3241 local delayed = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 or fonts . handlers . typethree
3242 for i = 1 , nofstrikes do
3243 local strike = strikes [ i ]
3244 local strikeppem = strike . ppem
3245 local strikeppi = strike . ppi
3246 local strikeoffset = strike . offset
3247 setposition ( f , strikeoffset )
3248 for i = 0 , nofglyphs do
3249 glyphs [ i ] = readulong ( f )
3250 end
3251 local glyphoffset = glyphs [ 0 ]
3252 for i = 0 , nofglyphs -1 do
3253 local nextoffset = glyphs [ i + 1 ]
3254 if not shapes [ i ] then
3255 local datasize = nextoffset - glyphoffset
3256 if datasize > 0 then
3257 setposition ( f , strikeoffset + glyphoffset )
3258 local x = readshort ( f )
3259 local y = readshort ( f )
3260 local tag = readtag ( f )
3261 local size = datasize - 8
3262 local data = nil
3263 local offset = nil
3264 if delayed then
3265 offset = getposition ( f )
3266 data = nil
3267 else
3268 data = readstring ( f , size )
3269 size = nil
3270 end
3271 shapes [ i ] = {
3272 x = x ,
3273 y = y ,
3274 o = offset ,
3275 s = size ,
3276 data = data ,
3277
3278
3279
3280 }
3281 done = done + 1
3282 if done = = nofglyphs then
3283 break
3284 end
3285 end
3286 end
3287 glyphoffset = nextoffset
3288 end
3289 end
3290 fontdata . pngshapes = shapes
3291 end
3292end
3293
3294
3295
3296
3297do
3298
3299 local function getmetrics ( f )
3300 return {
3301 ascender = readinteger ( f ) ,
3302 descender = readinteger ( f ) ,
3303 widthmax = readuinteger ( f ) ,
3304 caretslopedumerator = readinteger ( f ) ,
3305 caretslopedenominator = readinteger ( f ) ,
3306 caretoffset = readinteger ( f ) ,
3307 minorigin = readinteger ( f ) ,
3308 minadvance = readinteger ( f ) ,
3309 maxbefore = readinteger ( f ) ,
3310 minafter = readinteger ( f ) ,
3311 pad1 = readinteger ( f ) ,
3312 pad2 = readinteger ( f ) ,
3313 }
3314 end
3315
3316
3317
3318 local function getbigmetrics ( f )
3319
3320 return {
3321 height = readuinteger ( f ) ,
3322 width = readuinteger ( f ) ,
3323 horiBearingX = readinteger ( f ) ,
3324 horiBearingY = readinteger ( f ) ,
3325 horiAdvance = readuinteger ( f ) ,
3326 vertBearingX = readinteger ( f ) ,
3327 vertBearingY = readinteger ( f ) ,
3328 vertAdvance = readuinteger ( f ) ,
3329 }
3330 end
3331
3332 local function getsmallmetrics ( f )
3333
3334 return {
3335 height = readuinteger ( f ) ,
3336 width = readuinteger ( f ) ,
3337 bearingX = readinteger ( f ) ,
3338 bearingY = readinteger ( f ) ,
3339 advance = readuinteger ( f ) ,
3340 }
3341 end
3342
3343 function readers . cblc ( f , fontdata , specification )
3344
3345 local ctdttableoffset = gotodatatable ( f , fontdata , " cbdt " , specification . glyphs )
3346 if not ctdttableoffset then
3347 return
3348 end
3349 local cblctableoffset = gotodatatable ( f , fontdata , " cblc " , specification . glyphs )
3350 if cblctableoffset then
3351 local majorversion = readushort ( f )
3352 local minorversion = readushort ( f )
3353 local nofsizetables = readulong ( f )
3354 local sizetables = { }
3355 local shapes = { }
3356 local subtables = { }
3357 for i = 1 , nofsizetables do
3358 sizetables [ i ] = {
3359 subtables = readulong ( f ) ,
3360 indexsize = readulong ( f ) ,
3361 nofsubtables = readulong ( f ) ,
3362 colorref = readulong ( f ) ,
3363 hormetrics = getmetrics ( f ) ,
3364 vermetrics = getmetrics ( f ) ,
3365 firstindex = readushort ( f ) ,
3366 lastindex = readushort ( f ) ,
3367 ppemx = readbyte ( f ) ,
3368 ppemy = readbyte ( f ) ,
3369 bitdepth = readbyte ( f ) ,
3370 flags = readbyte ( f ) ,
3371 }
3372 end
3373 sort ( sizetables , function ( a , b )
3374 if b . ppemx = = a . ppemx then
3375 return b . bitdepth < a . bitdepth
3376 else
3377 return b . ppemx < a . ppemx
3378 end
3379 end )
3380 for i = 1 , nofsizetables do
3381 local s = sizetables [ i ]
3382 local d = false
3383 for j = s . firstindex , s . lastindex do
3384 if not shapes [ j ] then
3385 shapes [ j ] = i
3386 d = true
3387 end
3388 end
3389 if d then
3390 s . used = true
3391 end
3392 end
3393 for i = 1 , nofsizetables do
3394 local s = sizetables [ i ]
3395 if s . used then
3396 local offset = s . subtables
3397 setposition ( f , cblctableoffset + offset )
3398 for j = 1 , s . nofsubtables do
3399 local firstindex = readushort ( f )
3400 local lastindex = readushort ( f )
3401 local tableoffset = readulong ( f ) + offset
3402 for k = firstindex , lastindex do
3403 if shapes [ k ] = = i then
3404 local s = subtables [ tableoffset ]
3405 if not s then
3406 s = {
3407 firstindex = firstindex ,
3408 lastindex = lastindex ,
3409 }
3410 subtables [ tableoffset ] = s
3411 end
3412 shapes [ k ] = s
3413 end
3414 end
3415 end
3416 end
3417 end
3418
3419
3420
3421
3422 for offset , subtable in sortedhash ( subtables ) do
3423 local tabletype = readushort ( f )
3424 subtable . format = readushort ( f )
3425 local baseoffset = readulong ( f ) + ctdttableoffset
3426 local offsets = { }
3427 local metrics = nil
3428 if tabletype = = 1 then
3429
3430 for i = subtable . firstindex , subtable . lastindex do
3431 offsets [ i ] = readulong ( f ) + baseoffset
3432 end
3433 skipbytes ( f , 4 )
3434 elseif tabletype = = 2 then
3435 local size = readulong ( f )
3436 local done = baseoffset
3437 metrics = getbigmetrics ( f )
3438 for i = subtable . firstindex , subtable . lastindex do
3439 offsets [ i ] = done
3440 done = done + size
3441 end
3442 elseif tabletype = = 3 then
3443
3444 local n = subtable . lastindex - subtable . firstindex + 2
3445 for i = subtable . firstindex , subtable . lastindex do
3446 offsets [ i ] = readushort ( f ) + baseoffset
3447 end
3448 if math . odd ( n ) then
3449 skipbytes ( f , 4 )
3450 else
3451 skipbytes ( f , 2 )
3452 end
3453 elseif tabletype = = 4 then
3454 for i = 1 , readulong ( f ) do
3455 offsets [ readushort ( f ) ] = readushort ( f ) + baseoffset
3456 end
3457 elseif tabletype = = 5 then
3458 local size = readulong ( f )
3459 local done = baseoffset
3460 metrics = getbigmetrics ( f )
3461 local n = readulong ( f )
3462 for i = 1 , n do
3463 offsets [ readushort ( f ) ] = done
3464 done = done + size
3465 end
3466 if math . odd ( n ) then
3467 skipbytes ( f , 2 )
3468 end
3469 else
3470 return
3471 end
3472 subtable . offsets = offsets
3473 subtable . metrics = metrics
3474 end
3475
3476
3477
3478
3479 local default = { width = 0 , height = 0 }
3480 local glyphs = fontdata . glyphs
3481 local delayed = CONTEXTLMTXMODE and CONTEXTLMTXMODE > 0 or fonts . handlers . typethree
3482
3483 for index , subtable in sortedhash ( shapes ) do
3484 if type ( subtable ) = = " table " then
3485 local data = nil
3486 local size = nil
3487 local metrics = default
3488 local format = subtable . format
3489 local offset = subtable . offsets [ index ]
3490 setposition ( f , offset )
3491 if format = = 17 then
3492 metrics = getsmallmetrics ( f )
3493 size = true
3494 elseif format = = 18 then
3495 metrics = getbigmetrics ( f )
3496 size = true
3497 elseif format = = 19 then
3498 metrics = subtable . metrics
3499 size = true
3500 else
3501
3502 end
3503 if size then
3504 size = readulong ( f )
3505 if delayed then
3506 offset = getposition ( f )
3507 data = nil
3508 else
3509 offset = nil
3510 data = readstring ( f , size )
3511 size = nil
3512 end
3513 else
3514 offset = nil
3515 end
3516 local x = metrics . width
3517 local y = metrics . height
3518 shapes [ index ] = {
3519 x = x ,
3520 y = y ,
3521 o = offset ,
3522 s = size ,
3523 data = data ,
3524 }
3525
3526
3527 local glyph = glyphs [ index ]
3528 if not glyph . boundingbox then
3529 local width = glyph . width
3530 local height = width * y / x
3531 glyph . boundingbox = { 0 , 0 , width , height }
3532 end
3533 else
3534 shapes [ index ] = {
3535 x = 0 ,
3536 y = 0 ,
3537 data = " " ,
3538 }
3539 end
3540 end
3541
3542 fontdata . pngshapes = shapes
3543 end
3544 end
3545
3546 function readers . cbdt ( f , fontdata , specification )
3547
3548
3549
3550
3551
3552 end
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569end
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588function readers . stat ( f , fontdata , specification )
3589 local tableoffset = gotodatatable ( f , fontdata , " stat " , true )
3590 if tableoffset then
3591 local extras = fontdata . extras
3592 local version = readulong ( f )
3593 local axissize = readushort ( f )
3594 local nofaxis = readushort ( f )
3595 local axisoffset = readulong ( f )
3596 local nofvalues = readushort ( f )
3597 local valuesoffset = readulong ( f )
3598 local fallbackname = extras [ readushort ( f ) ]
3599 local axis = { }
3600 local values = { }
3601 setposition ( f , tableoffset + axisoffset )
3602 for i = 1 , nofaxis do
3603 local tag = readtag ( f )
3604 axis [ i ] = {
3605 tag = tag ,
3606 name = lower ( extras [ readushort ( f ) ] or tag ) ,
3607 ordering = readushort ( f ) ,
3608 variants = { }
3609 }
3610 end
3611
3612
3613
3614
3615
3616
3617 setposition ( f , tableoffset + valuesoffset )
3618 for i = 1 , nofvalues do
3619 values [ i ] = readushort ( f )
3620 end
3621 for i = 1 , nofvalues do
3622 setposition ( f , tableoffset + valuesoffset + values [ i ] )
3623 local format = readushort ( f )
3624 local index = readushort ( f ) + 1
3625 local flags = readushort ( f )
3626 local name = lower ( extras [ readushort ( f ) ] or " no name " )
3627 local value = readfixed ( f )
3628 local variant
3629 if format = = 1 then
3630 variant = {
3631 flags = flags ,
3632 name = name ,
3633 value = value ,
3634 }
3635 elseif format = = 2 then
3636 variant = {
3637 flags = flags ,
3638 name = name ,
3639 value = value ,
3640 minimum = readfixed ( f ) ,
3641 maximum = readfixed ( f ) ,
3642 }
3643 elseif format = = 3 then
3644 variant = {
3645 flags = flags ,
3646 name = name ,
3647 value = value ,
3648 link = readfixed ( f ) ,
3649 }
3650 end
3651 insert ( axis [ index ] . variants , variant )
3652 end
3653 sort ( axis , function ( a , b )
3654 return a . ordering < b . ordering
3655 end )
3656 for i = 1 , # axis do
3657 local a = axis [ i ]
3658 sort ( a . variants , function ( a , b )
3659 return a . name < b . name
3660 end )
3661 a . ordering = nil
3662 end
3663 setvariabledata ( fontdata , " designaxis " , axis )
3664 setvariabledata ( fontdata , " fallbackname " , fallbackname )
3665 end
3666end
3667
3668
3669
3670
3671
3672function readers . avar ( f , fontdata , specification )
3673 local tableoffset = gotodatatable ( f , fontdata , " avar " , true )
3674 if tableoffset then
3675
3676 local function collect ( )
3677 local nofvalues = readushort ( f )
3678 local values = { }
3679 local lastfrom = false
3680 local lastto = false
3681 for i = 1 , nofvalues do
3682 local from = read2dot14 ( f )
3683 local to = read2dot14 ( f )
3684 if lastfrom and from < = lastfrom then
3685
3686 elseif lastto and to > = lastto then
3687
3688 else
3689 values [ # values + 1 ] = { from , to }
3690 lastfrom , lastto = from , to
3691 end
3692 end
3693 nofvalues = # values
3694 if nofvalues > 2 then
3695 local some = values [ 1 ]
3696 if some [ 1 ] = = -1 and some [ 2 ] = = -1 then
3697 some = values [ nofvalues ]
3698 if some [ 1 ] = = 1 and some [ 2 ] = = 1 then
3699 for i = 2 , nofvalues -1 do
3700 some = values [ i ]
3701 if some [ 1 ] = = 0 and some [ 2 ] = = 0 then
3702 return values
3703 end
3704 end
3705 end
3706 end
3707 end
3708 return false
3709 end
3710
3711 local version = readulong ( f )
3712 local reserved = readushort ( f )
3713 local nofaxis = readushort ( f )
3714 local segments = { }
3715 for i = 1 , nofaxis do
3716 segments [ i ] = collect ( )
3717 end
3718 setvariabledata ( fontdata , " segments " , segments )
3719 end
3720end
3721
3722function readers . fvar ( f , fontdata , specification )
3723 local tableoffset = gotodatatable ( f , fontdata , " fvar " , true )
3724 if tableoffset then
3725 local version = readulong ( f )
3726 local offsettoaxis = tableoffset + readushort ( f )
3727 local reserved = skipshort ( f )
3728
3729 local nofaxis = readushort ( f )
3730 local sizeofaxis = readushort ( f )
3731
3732 local nofinstances = readushort ( f )
3733 local sizeofinstances = readushort ( f )
3734
3735 local extras = fontdata . extras
3736 local axis = { }
3737 local instances = { }
3738
3739 setposition ( f , offsettoaxis )
3740
3741 for i = 1 , nofaxis do
3742 axis [ i ] = {
3743 tag = readtag ( f ) ,
3744 minimum = readfixed ( f ) ,
3745 default = readfixed ( f ) ,
3746 maximum = readfixed ( f ) ,
3747 flags = readushort ( f ) ,
3748 name = lower ( extras [ readushort ( f ) ] or " bad name " ) ,
3749 }
3750 local n = sizeofaxis - 20
3751 if n > 0 then
3752 skipbytes ( f , n )
3753 elseif n < 0 then
3754
3755 end
3756 end
3757
3758 local nofbytes = 2 + 2 + 2 + nofaxis * 4
3759 local readpsname = nofbytes < = sizeofinstances
3760 local skippable = sizeofinstances - nofbytes
3761 for i = 1 , nofinstances do
3762 local subfamid = readushort ( f )
3763 local flags = readushort ( f )
3764 local values = { }
3765 for i = 1 , nofaxis do
3766 values [ i ] = {
3767 axis = axis [ i ] . tag ,
3768 value = readfixed ( f ) ,
3769 }
3770 end
3771 local psnameid = readpsname and readushort ( f ) or 0xFFFF
3772 if subfamid = = 2 or subfamid = = 17 then
3773
3774 elseif subfamid = = 0xFFFF then
3775 subfamid = nil
3776 elseif subfamid < = 256 or subfamid > = 32768 then
3777 subfamid = nil
3778 end
3779 if psnameid = = 6 then
3780
3781 elseif psnameid = = 0xFFFF then
3782 psnameid = nil
3783 elseif psnameid < = 256 or psnameid > = 32768 then
3784 psnameid = nil
3785 end
3786 instances [ i ] = {
3787
3788 subfamily = extras [ subfamid ] ,
3789 psname = psnameid and extras [ psnameid ] or nil ,
3790 values = values ,
3791 }
3792 if skippable > 0 then
3793 skipbytes ( f , skippable )
3794 end
3795 end
3796 setvariabledata ( fontdata , " axis " , axis )
3797 setvariabledata ( fontdata , " instances " , instances )
3798 end
3799end
3800
3801function readers . hvar ( f , fontdata , specification )
3802 local factors = specification . factors
3803 if not factors then
3804 return
3805 end
3806 local tableoffset = gotodatatable ( f , fontdata , " hvar " , specification . variable )
3807 if not tableoffset then
3808 return
3809 end
3810
3811 local version = readulong ( f )
3812 local variationoffset = tableoffset + readulong ( f )
3813 local advanceoffset = tableoffset + readulong ( f )
3814 local lsboffset = tableoffset + readulong ( f )
3815 local rsboffset = tableoffset + readulong ( f )
3816
3817 local regions = { }
3818 local variations = { }
3819 local innerindex = { }
3820 local outerindex = { }
3821
3822 if variationoffset > 0 then
3823 regions , deltas = readvariationdata ( f , variationoffset , factors )
3824 end
3825
3826 if not regions then
3827
3828 return
3829 end
3830
3831 if advanceoffset > 0 then
3832
3833
3834
3835
3836
3837
3838
3839
3840 setposition ( f , advanceoffset )
3841 local format = readushort ( f )
3842 local mapcount = readushort ( f )
3843 local entrysize = rshift ( band ( format , 0x0030 ) , 4 ) + 1
3844 local nofinnerbits = band ( format , 0x000F ) + 1
3845 local innermask = lshift ( 1 , nofinnerbits ) - 1
3846 local readcardinal = read_cardinal [ entrysize ]
3847 for i = 0 , mapcount -1 do
3848 local mapdata = readcardinal ( f )
3849 outerindex [ i ] = rshift ( mapdata , nofinnerbits )
3850 innerindex [ i ] = band ( mapdata , innermask )
3851 end
3852
3853 setvariabledata ( fontdata , " hvarwidths " , true )
3854 local glyphs = fontdata . glyphs
3855 for i = 0 , fontdata . nofglyphs -1 do
3856 local glyph = glyphs [ i ]
3857 local width = glyph . width
3858 if width then
3859 local outer = outerindex [ i ] or 0
3860 local inner = innerindex [ i ] or i
3861 if outer and inner then
3862 local delta = deltas [ outer + 1 ]
3863 if delta then
3864 local d = delta . deltas [ inner + 1 ]
3865 if d then
3866 local scales = delta . scales
3867 local deltaw = 0
3868 for i = 1 , # scales do
3869 local di = d [ i ]
3870 if di then
3871 deltaw = deltaw + scales [ i ] * di
3872 else
3873 break
3874 end
3875 end
3876
3877
3878 glyph . width = width + round ( deltaw )
3879 end
3880 end
3881 end
3882 end
3883 end
3884
3885 end
3886
3887
3888
3889
3890
3891
3892
3893
3894
3895
3896
3897end
3898
3899function readers . vvar ( f , fontdata , specification )
3900 if not specification . variable then
3901 return
3902 end
3903end
3904
3905function readers . mvar ( f , fontdata , specification )
3906 local tableoffset = gotodatatable ( f , fontdata , " mvar " , specification . variable )
3907 if tableoffset then
3908 local version = readulong ( f )
3909 local reserved = skipshort ( f , 1 )
3910 local recordsize = readushort ( f )
3911 local nofrecords = readushort ( f )
3912 local offsettostore = tableoffset + readushort ( f )
3913 local dimensions = { }
3914 local factors = specification . factors
3915 if factors then
3916 local regions , deltas = readvariationdata ( f , offsettostore , factors )
3917 for i = 1 , nofrecords do
3918 local tag = readtag ( f )
3919 local var = variabletags [ tag ]
3920 if var then
3921 local outer = readushort ( f )
3922 local inner = readushort ( f )
3923 local delta = deltas [ outer + 1 ]
3924 if delta then
3925 local d = delta . deltas [ inner + 1 ]
3926 if d then
3927 local scales = delta . scales
3928 local dd = 0
3929 for i = 1 , # scales do
3930 dd = dd + scales [ i ] * d [ i ]
3931 end
3932 var ( fontdata , round ( dd ) )
3933 end
3934 end
3935 else
3936 skipshort ( f , 2 )
3937 end
3938 if recordsize > 8 then
3939 skipbytes ( recordsize -8 )
3940 end
3941 end
3942 end
3943
3944 end
3945end
3946 |