1if not modules then modules = { } end modules [ ' font-ttf ' ] = {
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
35local next , type , unpack = next , type , unpack
36local band , rshift = bit32 . band , bit32 . rshift
37local sqrt , round = math . sqrt , math . round
38local char , rep = string . char , string . rep
39local concat = table . concat
40local idiv = number . idiv
41local setmetatableindex = table . setmetatableindex
42
43local report = logs . reporter ( " otf reader " , " ttf " )
44
45local trace_deltas = false
46
47local readers = fonts . handlers . otf . readers
48local streamreader = readers . streamreader
49
50local setposition = streamreader . setposition
51local getposition = streamreader . getposition
52local skipbytes = streamreader . skip
53local readbyte = streamreader . readcardinal1
54local readushort = streamreader . readcardinal2
55local readulong = streamreader . readcardinal4
56local readchar = streamreader . readinteger1
57local readshort = streamreader . readinteger2
58local read2dot14 = streamreader . read2dot14
59local readinteger = streamreader . readinteger1
60local readcardinaltable = streamreader . readcardinaltable
61local readintegertable = streamreader . readintegertable
62
63directives . register ( " fonts.streamreader " , function ( )
64
65 streamreader = utilities . streams
66
67 setposition = streamreader . setposition
68 getposition = streamreader . getposition
69 skipbytes = streamreader . skip
70 readbyte = streamreader . readcardinal1
71 readushort = streamreader . readcardinal2
72 readulong = streamreader . readcardinal4
73 readchar = streamreader . readinteger1
74 readshort = streamreader . readinteger2
75 read2dot14 = streamreader . read2dot14
76 readinteger = streamreader . readinteger1
77 readcardinaltable = streamreader . readcardinaltable
78 readintegertable = streamreader . readintegertable
79
80end )
81
82local short = 2
83local ushort = 2
84local ulong = 4
85
86local helpers = readers . helpers
87local gotodatatable = helpers . gotodatatable
88
89local function mergecomposites ( glyphs , shapes )
90
91
92
93 local function merge ( index , shape , components )
94 local contours = { }
95 local points = { }
96 local nofcontours = 0
97 local nofpoints = 0
98 local offset = 0
99 local deltas = shape . deltas
100 for i = 1 , # components do
101 local component = components [ i ]
102 local subindex = component . index
103 local subshape = shapes [ subindex ]
104 local subcontours = subshape . contours
105 local subpoints = subshape . points
106 if not subcontours then
107 local subcomponents = subshape . components
108 if subcomponents then
109 subcontours , subpoints = merge ( subindex , subshape , subcomponents )
110 end
111 end
112 if subpoints then
113 local matrix = component . matrix
114 local xscale = matrix [ 1 ]
115 local xrotate = matrix [ 2 ]
116 local yrotate = matrix [ 3 ]
117 local yscale = matrix [ 4 ]
118 local xoffset = matrix [ 5 ]
119 local yoffset = matrix [ 6 ]
120 local count = # subpoints
121 if xscale = = 1 and yscale = = 1 and xrotate = = 0 and yrotate = = 0 then
122 for i = 1 , count do
123 local p = subpoints [ i ]
124 nofpoints = nofpoints + 1
125 points [ nofpoints ] = {
126 p [ 1 ] + xoffset ,
127 p [ 2 ] + yoffset ,
128 p [ 3 ]
129 }
130 end
131 else
132 for i = 1 , count do
133 local p = subpoints [ i ]
134 local x = p [ 1 ]
135 local y = p [ 2 ]
136 nofpoints = nofpoints + 1
137 points [ nofpoints ] = {
138 xscale * x + xrotate * y + xoffset ,
139 yscale * y + yrotate * x + yoffset ,
140 p [ 3 ]
141 }
142 end
143 end
144 local subcount = # subcontours
145 if subcount = = 1 then
146 nofcontours = nofcontours + 1
147 contours [ nofcontours ] = offset + subcontours [ 1 ]
148 else
149 for i = 1 , # subcontours do
150 nofcontours = nofcontours + 1
151 contours [ nofcontours ] = offset + subcontours [ i ]
152 end
153 end
154 offset = offset + count
155 else
156 report ( " missing contours composite %s, component %s of %s, glyph %s " , index , i , # components , subindex )
157 end
158 end
159 shape . points = points
160 shape . contours = contours
161 shape . components = nil
162 return contours , points
163 end
164
165
166 for index = 0 , # glyphs -1 do
167 local shape = shapes [ index ]
168 if shape then
169 local components = shape . components
170 if components then
171 merge ( index , shape , components )
172 end
173 end
174 end
175
176end
177
178local function readnothing ( f )
179 return {
180 type = " nothing " ,
181 }
182end
183
184
185
186local function curveto ( m_x , m_y , l_x , l_y , r_x , r_y )
187 return
188 l_x + 2 / 3 * ( m_x - l_x ) , l_y + 2 / 3 * ( m_y - l_y ) ,
189 r_x + 2 / 3 * ( m_x - r_x ) , r_y + 2 / 3 * ( m_y - r_y ) ,
190 r_x , r_y , " c "
191end
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206local function applyaxis ( glyph , shape , deltas , dowidth )
207 local points = shape . points
208 if points then
209 local nofpoints = # points
210 local h = nofpoints + 2
211 local l = nofpoints + 1
212
213
214 local dw = 0
215 local dl = 0
216 for i = 1 , # deltas do
217 local deltaset = deltas [ i ]
218 local xvalues = deltaset . xvalues
219 local yvalues = deltaset . yvalues
220 local dpoints = deltaset . points
221 local factor = deltaset . factor
222 if dpoints then
223
224 local nofdpoints = # dpoints
225 for i = 1 , nofdpoints do
226 local d = dpoints [ i ]
227 local p = points [ d ]
228 if p then
229 if xvalues then
230 local x = xvalues [ i ]
231 if x and x ~ = 0 then
232 p [ 1 ] = p [ 1 ] + factor * x
233 end
234 end
235 if yvalues then
236 local y = yvalues [ i ]
237 if y and y ~ = 0 then
238 p [ 2 ] = p [ 2 ] + factor * y
239 end
240 end
241 elseif dowidth then
242
243
244
245
246 if d = = h then
247
248 local x = xvalues [ i ]
249 if x then
250 dw = dw + factor * x
251 end
252 elseif d = = l then
253 local x = xvalues [ i ]
254 if x then
255 dl = dl + factor * x
256 end
257 end
258 end
259 end
260 else
261 for i = 1 , nofpoints do
262 local p = points [ i ]
263 if xvalues then
264 local x = xvalues [ i ]
265 if x and x ~ = 0 then
266 p [ 1 ] = p [ 1 ] + factor * x
267 end
268 end
269 if yvalues then
270 local y = yvalues [ i ]
271 if y and y ~ = 0 then
272 p [ 2 ] = p [ 2 ] + factor * y
273 end
274 end
275 end
276 if dowidth then
277 local x = xvalues [ h ]
278 if x then
279 dw = dw + factor * x
280 end
281 local x = xvalues [ l ]
282 if x then
283 dl = dl + factor * x
284 end
285 end
286 end
287 end
288
289
290
291
292
293 if dowidth then
294 local width = glyph . width or 0
295
296 glyph . width = width + dw - dl
297 end
298 else
299 report ( " no points for glyph %a " , glyph . name )
300 end
301end
302
303
304
305
306local quadratic = false
307
308local function contours2outlines_normal ( glyphs , shapes )
309
310 for index = 0 , # glyphs -1 do
311 local shape = shapes [ index ]
312 if shape then
313 local glyph = glyphs [ index ]
314 local contours = shape . contours
315 local points = shape . points
316 if contours then
317 local nofcontours = # contours
318 local segments = { }
319 local nofsegments = 0
320 glyph . segments = segments
321 if nofcontours > 0 then
322 local px = 0
323 local py = 0
324 local first = 1
325 for i = 1 , nofcontours do
326 local last = contours [ i ]
327 if last > = first then
328 local first_pt = points [ first ]
329 local first_on = first_pt [ 3 ]
330
331 if first = = last then
332 first_pt [ 3 ] = " m "
333 nofsegments = nofsegments + 1
334 segments [ nofsegments ] = first_pt
335 else
336 local first_on = first_pt [ 3 ]
337 local last_pt = points [ last ]
338 local last_on = last_pt [ 3 ]
339 local start = 1
340 local control_pt = false
341 if first_on then
342 start = 2
343 else
344 if last_on then
345 first_pt = last_pt
346 else
347 first_pt = { ( first_pt [ 1 ] + last_pt [ 1 ] ) / 2 , ( first_pt [ 2 ] + last_pt [ 2 ] ) / 2 , false }
348 end
349 control_pt = first_pt
350 end
351 local x = first_pt [ 1 ]
352 local y = first_pt [ 2 ]
353 if not done then
354 xmin = x
355 ymin = y
356 xmax = x
357 ymax = y
358 done = true
359 end
360 nofsegments = nofsegments + 1
361 segments [ nofsegments ] = { x , y , " m " }
362 if not quadratic then
363 px = x
364 py = y
365 end
366 local previous_pt = first_pt
367 for i = first , last do
368 local current_pt = points [ i ]
369 local current_on = current_pt [ 3 ]
370 local previous_on = previous_pt [ 3 ]
371 if previous_on then
372 if current_on then
373
374 local x , y = current_pt [ 1 ] , current_pt [ 2 ]
375 nofsegments = nofsegments + 1
376 segments [ nofsegments ] = { x , y , " l " }
377 if not quadratic then
378 px , py = x , y
379 end
380 else
381 control_pt = current_pt
382 end
383 elseif current_on then
384 local x1 = control_pt [ 1 ]
385 local y1 = control_pt [ 2 ]
386 local x2 = current_pt [ 1 ]
387 local y2 = current_pt [ 2 ]
388 nofsegments = nofsegments + 1
389 if quadratic then
390 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , " q " }
391 else
392 x1 , y1 , x2 , y2 , px , py = curveto ( x1 , y1 , px , py , x2 , y2 )
393 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , px , py , " c " }
394 end
395 control_pt = false
396 else
397 local x2 = ( previous_pt [ 1 ] + current_pt [ 1 ] ) / 2
398 local y2 = ( previous_pt [ 2 ] + current_pt [ 2 ] ) / 2
399 local x1 = control_pt [ 1 ]
400 local y1 = control_pt [ 2 ]
401 nofsegments = nofsegments + 1
402 if quadratic then
403 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , " q " }
404 else
405 x1 , y1 , x2 , y2 , px , py = curveto ( x1 , y1 , px , py , x2 , y2 )
406 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , px , py , " c " }
407 end
408 control_pt = current_pt
409 end
410 previous_pt = current_pt
411 end
412 if first_pt = = last_pt then
413
414 else
415 nofsegments = nofsegments + 1
416 local x2 = first_pt [ 1 ]
417 local y2 = first_pt [ 2 ]
418 if not control_pt then
419 segments [ nofsegments ] = { x2 , y2 , " l " }
420 elseif quadratic then
421 local x1 = control_pt [ 1 ]
422 local y1 = control_pt [ 2 ]
423 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , " q " }
424 else
425 local x1 = control_pt [ 1 ]
426 local y1 = control_pt [ 2 ]
427 x1 , y1 , x2 , y2 , px , py = curveto ( x1 , y1 , px , py , x2 , y2 )
428 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , px , py , " c " }
429
430 end
431 end
432 end
433 end
434 first = last + 1
435 end
436 end
437 end
438 end
439 end
440end
441
442local function contours2outlines_shaped ( glyphs , shapes , keepcurve )
443
444 for index = 0 , # glyphs -1 do
445 local shape = shapes [ index ]
446 if shape then
447 local glyph = glyphs [ index ]
448 local contours = shape . contours
449 local points = shape . points
450 if contours then
451 local nofcontours = # contours
452 local segments = keepcurve and { } or nil
453 local nofsegments = 0
454 if keepcurve then
455 glyph . segments = segments
456 end
457 if nofcontours > 0 then
458 local xmin , ymin , xmax , ymax , done = 0 , 0 , 0 , 0 , false
459 local px , py = 0 , 0
460 local first = 1
461 for i = 1 , nofcontours do
462 local last = contours [ i ]
463 if last > = first then
464 local first_pt = points [ first ]
465 local first_on = first_pt [ 3 ]
466
467 if first = = last then
468
469 if keepcurve then
470 first_pt [ 3 ] = " m "
471 nofsegments = nofsegments + 1
472 segments [ nofsegments ] = first_pt
473 end
474 else
475 local first_on = first_pt [ 3 ]
476 local last_pt = points [ last ]
477 local last_on = last_pt [ 3 ]
478 local start = 1
479 local control_pt = false
480 if first_on then
481 start = 2
482 else
483 if last_on then
484 first_pt = last_pt
485 else
486 first_pt = { ( first_pt [ 1 ] + last_pt [ 1 ] ) / 2 , ( first_pt [ 2 ] + last_pt [ 2 ] ) / 2 , false }
487 end
488 control_pt = first_pt
489 end
490 local x = first_pt [ 1 ]
491 local y = first_pt [ 2 ]
492 if not done then
493 xmin , ymin , xmax , ymax = x , y , x , y
494 done = true
495 else
496 if x < xmin then xmin = x elseif x > xmax then xmax = x end
497 if y < ymin then ymin = y elseif y > ymax then ymax = y end
498 end
499 if keepcurve then
500 nofsegments = nofsegments + 1
501 segments [ nofsegments ] = { x , y , " m " }
502 end
503 if not quadratic then
504 px = x
505 py = y
506 end
507 local previous_pt = first_pt
508 for i = first , last do
509 local current_pt = points [ i ]
510 local current_on = current_pt [ 3 ]
511 local previous_on = previous_pt [ 3 ]
512 if previous_on then
513 if current_on then
514
515 local x = current_pt [ 1 ]
516 local y = current_pt [ 2 ]
517 if x < xmin then xmin = x elseif x > xmax then xmax = x end
518 if y < ymin then ymin = y elseif y > ymax then ymax = y end
519 if keepcurve then
520 nofsegments = nofsegments + 1
521 segments [ nofsegments ] = { x , y , " l " }
522 end
523 if not quadratic then
524 px = x
525 py = y
526 end
527 else
528 control_pt = current_pt
529 end
530 elseif current_on then
531 local x1 = control_pt [ 1 ]
532 local y1 = control_pt [ 2 ]
533 local x2 = current_pt [ 1 ]
534 local y2 = current_pt [ 2 ]
535 if quadratic then
536 if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
537 if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
538 if keepcurve then
539 nofsegments = nofsegments + 1
540 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , " q " }
541 end
542 else
543 x1 , y1 , x2 , y2 , px , py = curveto ( x1 , y1 , px , py , x2 , y2 )
544 if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
545 if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
546 if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
547 if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
548 if px < xmin then xmin = px elseif px > xmax then xmax = px end
549 if py < ymin then ymin = py elseif py > ymax then ymax = py end
550 if keepcurve then
551 nofsegments = nofsegments + 1
552 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , px , py , " c " }
553 end
554 end
555 control_pt = false
556 else
557 local x2 = ( previous_pt [ 1 ] + current_pt [ 1 ] ) / 2
558 local y2 = ( previous_pt [ 2 ] + current_pt [ 2 ] ) / 2
559 local x1 = control_pt [ 1 ]
560 local y1 = control_pt [ 2 ]
561 if quadratic then
562 if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
563 if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
564 if keepcurve then
565 nofsegments = nofsegments + 1
566 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , " q " }
567 end
568 else
569 x1 , y1 , x2 , y2 , px , py = curveto ( x1 , y1 , px , py , x2 , y2 )
570 if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
571 if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
572 if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
573 if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
574 if px < xmin then xmin = px elseif px > xmax then xmax = px end
575 if py < ymin then ymin = py elseif py > ymax then ymax = py end
576 if keepcurve then
577 nofsegments = nofsegments + 1
578 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , px , py , " c " }
579 end
580 end
581 control_pt = current_pt
582 end
583 previous_pt = current_pt
584 end
585 if first_pt = = last_pt then
586
587 elseif not control_pt then
588 if keepcurve then
589 nofsegments = nofsegments + 1
590 segments [ nofsegments ] = { first_pt [ 1 ] , first_pt [ 2 ] , " l " }
591 end
592 else
593 local x1 = control_pt [ 1 ]
594 local y1 = control_pt [ 2 ]
595 local x2 = first_pt [ 1 ]
596 local y2 = first_pt [ 2 ]
597 if x1 < xmin then xmin = x1 elseif x1 > xmax then xmax = x1 end
598 if y1 < ymin then ymin = y1 elseif y1 > ymax then ymax = y1 end
599 if quadratic then
600 if keepcurve then
601 nofsegments = nofsegments + 1
602 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , " q " }
603 end
604 else
605 x1 , y1 , x2 , y2 , px , py = curveto ( x1 , y1 , px , py , x2 , y2 )
606 if x2 < xmin then xmin = x2 elseif x2 > xmax then xmax = x2 end
607 if y2 < ymin then ymin = y2 elseif y2 > ymax then ymax = y2 end
608 if px < xmin then xmin = px elseif px > xmax then xmax = px end
609 if py < ymin then ymin = py elseif py > ymax then ymax = py end
610 if keepcurve then
611 nofsegments = nofsegments + 1
612 segments [ nofsegments ] = { x1 , y1 , x2 , y2 , px , py , " c " }
613 end
614
615 end
616 end
617 end
618 end
619 first = last + 1
620 end
621 glyph . boundingbox = { round ( xmin ) , round ( ymin ) , round ( xmax ) , round ( ymax ) }
622 end
623 end
624 end
625 end
626end
627
628
629
630local c_zero = char ( 0 )
631local s_zero = char ( 0 , 0 )
632
633
634
635
636
637local function toushort ( n )
638 return char ( band ( rshift ( n , 8 ) , 0xFF ) , band ( n , 0xFF ) )
639
640end
641
642local function toshort ( n )
643 if n < 0 then
644 n = n + 0x10000
645 end
646 return char ( band ( rshift ( n , 8 ) , 0xFF ) , band ( n , 0xFF ) )
647
648end
649
650
651
652local chars = setmetatableindex ( function ( t , k )
653 for i = 0 , 255 do local v = char ( i ) t [ i ] = v end return t [ k ]
654end )
655
656local function repackpoints ( glyphs , shapes )
657 local noboundingbox = { 0 , 0 , 0 , 0 }
658 local result = { }
659 local xpoints = { }
660 local ypoints = { }
661 for index = 0 , # glyphs -1 do
662 local shape = shapes [ index ]
663 if shape then
664 local r = 0
665 local glyph = glyphs [ index ]
666 local contours = shape . contours
667 local nofcontours = contours and # contours or 0
668 local boundingbox = glyph . boundingbox or noboundingbox
669 r = r + 1 result [ r ] = toshort ( nofcontours )
670 r = r + 1 result [ r ] = toshort ( boundingbox [ 1 ] )
671 r = r + 1 result [ r ] = toshort ( boundingbox [ 2 ] )
672 r = r + 1 result [ r ] = toshort ( boundingbox [ 3 ] )
673 r = r + 1 result [ r ] = toshort ( boundingbox [ 4 ] )
674 if nofcontours > 0 then
675 for i = 1 , nofcontours do
676 r = r + 1 result [ r ] = toshort ( contours [ i ] -1 )
677 end
678 r = r + 1 result [ r ] = s_zero
679 local points = shape . points
680 local currentx = 0
681 local currenty = 0
682
683
684 local x = 0
685 local y = 0
686 local lastflag = nil
687 local nofflags = 0
688 for i = 1 , # points do
689 local pt = points [ i ]
690 local px = pt [ 1 ]
691 local py = pt [ 2 ]
692 local fl = pt [ 3 ] and 0x01 or 0x00
693 if px = = currentx then
694 fl = fl + 0x10
695 else
696 local dx = round ( px - currentx )
697 x = x + 1
698 if dx < -255 or dx > 255 then
699 xpoints [ x ] = toshort ( dx )
700 elseif dx < 0 then
701 fl = fl + 0x02
702
703 xpoints [ x ] = chars [ - dx ]
704 elseif dx > 0 then
705 fl = fl + 0x12
706
707 xpoints [ x ] = chars [ dx ]
708 else
709 fl = fl + 0x02
710 xpoints [ x ] = c_zero
711 end
712 end
713 if py = = currenty then
714 fl = fl + 0x20
715 else
716 local dy = round ( py - currenty )
717 y = y + 1
718 if dy < -255 or dy > 255 then
719 ypoints [ y ] = toshort ( dy )
720 elseif dy < 0 then
721 fl = fl + 0x04
722
723 ypoints [ y ] = chars [ - dy ]
724 elseif dy > 0 then
725 fl = fl + 0x24
726
727 ypoints [ y ] = chars [ dy ]
728 else
729 fl = fl + 0x04
730 ypoints [ y ] = c_zero
731 end
732 end
733 currentx = px
734 currenty = py
735 if lastflag = = fl then
736 if nofflags = = 255 then
737
738 lastflag = lastflag + 0x08
739 r = r + 1 result [ r ] = char ( lastflag , nofflags -1 )
740 nofflags = 1
741 lastflag = fl
742 else
743 nofflags = nofflags + 1
744 end
745 else
746 if nofflags = = 1 then
747
748 r = r + 1 result [ r ] = chars [ lastflag ]
749 elseif nofflags = = 2 then
750 r = r + 1 result [ r ] = char ( lastflag , lastflag )
751 elseif nofflags > 2 then
752 lastflag = lastflag + 0x08
753 r = r + 1 result [ r ] = char ( lastflag , nofflags -1 )
754 end
755 nofflags = 1
756 lastflag = fl
757 end
758 end
759 if nofflags = = 1 then
760
761 r = r + 1 result [ r ] = chars [ lastflag ]
762 elseif nofflags = = 2 then
763 r = r + 1 result [ r ] = char ( lastflag , lastflag )
764 elseif nofflags > 2 then
765 lastflag = lastflag + 0x08
766 r = r + 1 result [ r ] = char ( lastflag , nofflags -1 )
767 end
768
769
770 r = r + 1 result [ r ] = concat ( xpoints , " " , 1 , x )
771 r = r + 1 result [ r ] = concat ( ypoints , " " , 1 , y )
772 end
773
774 local stream = concat ( result , " " , 1 , r )
775 local length = # stream
776 local padding = idiv ( length + 3 , 4 ) * 4 - length
777 if padding > 0 then
778
779 if padding = = 1 then
780 padding = " \0 "
781 elseif padding = = 2 then
782 padding = " \0\0 "
783 else
784 padding = " \0\0\0 "
785 end
786 padding = stream . . padding
787 end
788 glyph . stream = stream
789 end
790 end
791end
792
793
794
795local flags = { }
796
797local function readglyph ( f , nofcontours )
798 local points = { }
799
800 local contours = { }
801 for i = 1 , nofcontours do
802 contours [ i ] = readshort ( f ) + 1
803 end
804 local nofpoints = contours [ nofcontours ]
805 local nofinstructions = readushort ( f )
806 skipbytes ( f , nofinstructions )
807
808
809 local i = 1
810 while i < = nofpoints do
811 local flag = readbyte ( f )
812 flags [ i ] = flag
813 if band ( flag , 0x08 ) ~ = 0 then
814 local n = readbyte ( f )
815 if n = = 1 then
816 i = i + 1
817 flags [ i ] = flag
818 else
819 for j = 1 , n do
820 i = i + 1
821 flags [ i ] = flag
822 end
823 end
824 end
825 i = i + 1
826 end
827
828
829 local x = 0
830 for i = 1 , nofpoints do
831 local flag = flags [ i ]
832
833
834 if band ( flag , 0x02 ) ~ = 0 then
835 if band ( flag , 0x10 ) ~ = 0 then
836 x = x + readbyte ( f )
837 else
838 x = x - readbyte ( f )
839 end
840 elseif band ( flag , 0x10 ) ~ = 0 then
841
842 else
843 x = x + readshort ( f )
844 end
845 points [ i ] = { x , 0 , band ( flag , 0x01 ) ~ = 0 }
846 end
847 local y = 0
848 for i = 1 , nofpoints do
849 local flag = flags [ i ]
850
851
852 if band ( flag , 0x04 ) ~ = 0 then
853 if band ( flag , 0x20 ) ~ = 0 then
854 y = y + readbyte ( f )
855 else
856 y = y - readbyte ( f )
857 end
858 elseif band ( flag , 0x20 ) ~ = 0 then
859
860 else
861 y = y + readshort ( f )
862 end
863 points [ i ] [ 2 ] = y
864 end
865 return {
866 type = " glyph " ,
867 points = points ,
868 contours = contours ,
869 nofpoints = nofpoints ,
870 }
871end
872
873local function readcomposite ( f )
874 local components = { }
875 local nofcomponents = 0
876 local instructions = false
877 while true do
878 local flags = readushort ( f )
879 local index = readushort ( f )
880
881 local f_xyarg = band ( flags , 0x0002 ) ~ = 0
882
883
884
885
886
887
888
889
890
891 local f_offset = band ( flags , 0x0800 ) ~ = 0
892
893 local xscale = 1
894 local xrotate = 0
895 local yrotate = 0
896 local yscale = 1
897 local xoffset = 0
898 local yoffset = 0
899 local base = false
900 local reference = false
901 if f_xyarg then
902 if band ( flags , 0x0001 ) ~ = 0 then
903 xoffset = readshort ( f )
904 yoffset = readshort ( f )
905 else
906 xoffset = readchar ( f )
907 yoffset = readchar ( f )
908 end
909 else
910 if band ( flags , 0x0001 ) ~ = 0 then
911 base = readshort ( f )
912 reference = readshort ( f )
913 else
914 base = readchar ( f )
915 reference = readchar ( f )
916 end
917 end
918 if band ( flags , 0x0008 ) ~ = 0 then
919 xscale = read2dot14 ( f )
920 yscale = xscale
921 if f_xyarg and f_offset then
922 xoffset = xoffset * xscale
923 yoffset = yoffset * yscale
924 end
925 elseif band ( flags , 0x0040 ) ~ = 0 then
926 xscale = read2dot14 ( f )
927 yscale = read2dot14 ( f )
928 if f_xyarg and f_offset then
929 xoffset = xoffset * xscale
930 yoffset = yoffset * yscale
931 end
932 elseif band ( flags , 0x0080 ) ~ = 0 then
933 xscale = read2dot14 ( f )
934 xrotate = read2dot14 ( f )
935 yrotate = read2dot14 ( f )
936 yscale = read2dot14 ( f )
937 if f_xyarg and f_offset then
938 xoffset = xoffset * sqrt ( xscale ^ 2 + xrotate ^ 2 )
939 yoffset = yoffset * sqrt ( yrotate ^ 2 + yscale ^ 2 )
940 end
941 end
942 nofcomponents = nofcomponents + 1
943 components [ nofcomponents ] = {
944 index = index ,
945 usemine = band ( flags , 0x0200 ) ~ = 0 ,
946 round = band ( flags , 0x0006 ) ~ = 0 ,
947 base = base ,
948 reference = reference ,
949 matrix = { xscale , xrotate , yrotate , yscale , xoffset , yoffset } ,
950 }
951 if band ( flags , 0x0100 ) ~ = 0 then
952 instructions = true
953 end
954 if band ( flags , 0x0020 ) = = 0 then
955 break
956 end
957 end
958 return {
959 type = " composite " ,
960 components = components ,
961 }
962end
963
964
965
966
967
968
969
970
971
972function readers . loca ( f , fontdata , specification )
973 if specification . glyphs then
974 local datatable = fontdata . tables . loca
975 if datatable then
976
977 local offset = fontdata . tables . glyf . offset
978 local format = fontdata . fontheader . indextolocformat
979 local profile = fontdata . maximumprofile
980 local nofglyphs = profile and profile . nofglyphs
981 local locations = { }
982 setposition ( f , datatable . offset )
983 if format = = 1 then
984 if not nofglyphs then
985 nofglyphs = idiv ( datatable . length , 4 ) - 1
986 end
987 for i = 0 , nofglyphs do
988 locations [ i ] = offset + readulong ( f )
989 end
990 fontdata . nofglyphs = nofglyphs
991 else
992 if not nofglyphs then
993 nofglyphs = idiv ( datatable . length , 2 ) - 1
994 end
995 for i = 0 , nofglyphs do
996 locations [ i ] = offset + readushort ( f ) * 2
997 end
998 end
999 fontdata . nofglyphs = nofglyphs
1000 fontdata . locations = locations
1001 end
1002 end
1003end
1004
1005function readers . glyf ( f , fontdata , specification )
1006 local tableoffset = gotodatatable ( f , fontdata , " glyf " , specification . glyphs )
1007 if tableoffset then
1008 local locations = fontdata . locations
1009 if locations then
1010 local glyphs = fontdata . glyphs
1011 local nofglyphs = fontdata . nofglyphs
1012 local filesize = fontdata . filesize
1013 local nothing = { 0 , 0 , 0 , 0 }
1014 local shapes = { }
1015 local loadshapes = specification . shapes or specification . instance or specification . streams
1016 for index = 0 , nofglyphs -1 do
1017 local location = locations [ index ]
1018 local length = locations [ index + 1 ] - location
1019 if location > = filesize then
1020 report ( " discarding %s glyphs due to glyph location bug " , nofglyphs - index + 1 )
1021 fontdata . nofglyphs = index - 1
1022 fontdata . badfont = true
1023 break
1024 elseif length > 0 then
1025 setposition ( f , location )
1026 local nofcontours = readshort ( f )
1027 glyphs [ index ] . boundingbox = {
1028 readshort ( f ) ,
1029 readshort ( f ) ,
1030 readshort ( f ) ,
1031 readshort ( f ) ,
1032 }
1033 if not loadshapes then
1034
1035 elseif nofcontours = = 0 then
1036 shapes [ index ] = readnothing ( f )
1037 elseif nofcontours > 0 then
1038 shapes [ index ] = readglyph ( f , nofcontours )
1039 else
1040 shapes [ index ] = readcomposite ( f , nofcontours )
1041 end
1042 else
1043 if loadshapes then
1044 shapes [ index ] = readnothing ( f )
1045 end
1046 glyphs [ index ] . boundingbox = nothing
1047 end
1048 end
1049 if loadshapes then
1050 if readers . gvar then
1051 readers . gvar ( f , fontdata , specification , glyphs , shapes )
1052 end
1053 mergecomposites ( glyphs , shapes )
1054 if specification . instance then
1055 if specification . streams then
1056 repackpoints ( glyphs , shapes )
1057 else
1058 contours2outlines_shaped ( glyphs , shapes , specification . shapes )
1059 end
1060 elseif specification . shapes then
1061 if specification . streams then
1062 repackpoints ( glyphs , shapes )
1063 else
1064 contours2outlines_normal ( glyphs , shapes )
1065 end
1066 elseif specification . streams then
1067 repackpoints ( glyphs , shapes )
1068 end
1069 end
1070 end
1071 end
1072end
1073
1074
1075
1076
1077
1078local function readtuplerecord ( f , nofaxis )
1079 local record = { }
1080 for i = 1 , nofaxis do
1081 record [ i ] = read2dot14 ( f )
1082 end
1083 return record
1084end
1085
1086
1087
1088
1089local function readpoints ( f )
1090 local count = readbyte ( f )
1091 if count = = 0 then
1092
1093 return nil , 0
1094 else
1095 if count < 128 then
1096
1097 elseif band ( count , 0x80 ) ~ = 0 then
1098 count = band ( count , 0x7F ) * 256 + readbyte ( f )
1099 else
1100
1101 end
1102 local points = { }
1103 local p = 0
1104 local n = 1
1105 while p < count do
1106 local control = readbyte ( f )
1107 local runreader = band ( control , 0x80 ) ~ = 0 and readushort or readbyte
1108 local runlength = band ( control , 0x7F )
1109 for i = 1 , runlength + 1 do
1110 n = n + runreader ( f )
1111 p = p + 1
1112 points [ p ] = n
1113 end
1114 end
1115 return points , p
1116 end
1117end
1118
1119local function readdeltas ( f , nofpoints )
1120 local deltas = { }
1121 local p = 0
1122 local z = 0
1123 while nofpoints > 0 do
1124 local control = readbyte ( f )
1125if not control then
1126 break
1127end
1128 local allzero = band ( control , 0x80 ) ~ = 0
1129 local runlength = band ( control , 0x3F ) + 1
1130 if allzero then
1131 z = z + runlength
1132 else
1133 local runreader = band ( control , 0x40 ) ~ = 0 and readshort or readinteger
1134 if z > 0 then
1135 for i = 1 , z do
1136 p = p + 1
1137 deltas [ p ] = 0
1138 end
1139 z = 0
1140 end
1141 for i = 1 , runlength do
1142 p = p + 1
1143 deltas [ p ] = runreader ( f )
1144 end
1145 end
1146 nofpoints = nofpoints - runlength
1147 end
1148
1149
1150
1151
1152
1153
1154
1155 if p > 0 then
1156
1157 return deltas
1158 else
1159
1160 end
1161end
1162
1163local function readdeltas ( f , nofpoints )
1164 local deltas = { }
1165 local p = 0
1166 while nofpoints > 0 do
1167 local control = readbyte ( f )
1168 if control then
1169 local allzero = band ( control , 0x80 ) ~ = 0
1170 local runlength = band ( control , 0x3F ) + 1
1171 if allzero then
1172 for i = 1 , runlength do
1173 p = p + 1
1174 deltas [ p ] = 0
1175 end
1176 else
1177 local runreader = band ( control , 0x40 ) ~ = 0 and readshort or readinteger
1178 for i = 1 , runlength do
1179 p = p + 1
1180 deltas [ p ] = runreader ( f )
1181 end
1182 end
1183 nofpoints = nofpoints - runlength
1184 else
1185
1186 break
1187 end
1188 end
1189
1190 if p > 0 then
1191 return deltas
1192 else
1193
1194 end
1195end
1196
1197function readers . gvar ( f , fontdata , specification , glyphdata , shapedata )
1198
1199 local instance = specification . instance
1200 if not instance then
1201 return
1202 end
1203 local factors = specification . factors
1204 if not factors then
1205 return
1206 end
1207 local tableoffset = gotodatatable ( f , fontdata , " gvar " , specification . variable or specification . shapes )
1208 if tableoffset then
1209 local version = readulong ( f )
1210 local nofaxis = readushort ( f )
1211 local noftuples = readushort ( f )
1212 local tupleoffset = tableoffset + readulong ( f )
1213 local nofglyphs = readushort ( f )
1214 local flags = readushort ( f )
1215 local dataoffset = tableoffset + readulong ( f )
1216 local data = { }
1217 local tuples = { }
1218 local glyphdata = fontdata . glyphs
1219 local dowidth = not fontdata . variabledata . hvarwidths
1220
1221
1222 if band ( flags , 0x0001 ) ~ = 0 then
1223 for i = 1 , nofglyphs + 1 do
1224 data [ i ] = dataoffset + readulong ( f )
1225 end
1226 else
1227 for i = 1 , nofglyphs + 1 do
1228 data [ i ] = dataoffset + 2 * readushort ( f )
1229 end
1230 end
1231
1232 if noftuples > 0 then
1233 setposition ( f , tupleoffset )
1234 for i = 1 , noftuples do
1235 tuples [ i ] = readtuplerecord ( f , nofaxis )
1236 end
1237 end
1238 local nextoffset = false
1239 local startoffset = data [ 1 ]
1240 for i = 1 , nofglyphs do
1241 nextoffset = data [ i + 1 ]
1242 local glyph = glyphdata [ i -1 ]
1243 local name = trace_deltas and glyph . name
1244 if startoffset = = nextoffset then
1245 if name then
1246 report ( " no deltas for glyph %a " , name )
1247 end
1248 else
1249 local shape = shapedata [ i -1 ]
1250 if not shape then
1251 if name then
1252 report ( " no shape for glyph %a " , name )
1253 end
1254 else
1255 lastoffset = startoffset
1256 setposition ( f , startoffset )
1257 local flags = readushort ( f )
1258 local count = band ( flags , 0x0FFF )
1259 local offset = startoffset + readushort ( f )
1260 local deltas = { }
1261 local allpoints = ( shape . nofpoints or 0 )
1262 local shared = false
1263 local nofshared = 0
1264 if band ( flags , 0x8000 ) ~ = 0 then
1265
1266 local current = getposition ( f )
1267 setposition ( f , offset )
1268 shared , nofshared = readpoints ( f )
1269 offset = getposition ( f )
1270 setposition ( f , current )
1271
1272 end
1273 for j = 1 , count do
1274 local size = readushort ( f )
1275 local flags = readushort ( f )
1276 local index = band ( flags , 0x0FFF )
1277 local haspeak = band ( flags , 0x8000 ) ~ = 0
1278 local intermediate = band ( flags , 0x4000 ) ~ = 0
1279 local private = band ( flags , 0x2000 ) ~ = 0
1280 local peak = nil
1281 local start = nil
1282 local stop = nil
1283 local xvalues = nil
1284 local yvalues = nil
1285 local points = shared
1286 local nofpoints = nofshared
1287
1288 if haspeak then
1289 peak = readtuplerecord ( f , nofaxis )
1290
1291 else
1292 if index + 1 > # tuples then
1293 report ( " error, bad tuple index " , index )
1294 end
1295 peak = tuples [ index + 1 ]
1296 end
1297 if intermediate then
1298 start = readtuplerecord ( f , nofaxis )
1299 stop = readtuplerecord ( f , nofaxis )
1300
1301 end
1302
1303 if size > 0 then
1304 local current = getposition ( f )
1305
1306 setposition ( f , offset )
1307 if private then
1308 points , nofpoints = readpoints ( f )
1309 end
1310 if nofpoints = = 0 then
1311 nofpoints = allpoints + 4
1312 end
1313 if nofpoints > 0 then
1314
1315 xvalues = readdeltas ( f , nofpoints )
1316 yvalues = readdeltas ( f , nofpoints )
1317 end
1318
1319 offset = offset + size
1320
1321 setposition ( f , current )
1322 end
1323 if not xvalues and not yvalues then
1324 points = nil
1325 end
1326 local s = 1
1327 for i = 1 , nofaxis do
1328 local f = factors [ i ]
1329 local peak = peak and peak [ i ] or 0
1330
1331
1332 local start = start and start [ i ] or ( peak < 0 and peak or 0 )
1333 local stop = stop and stop [ i ] or ( peak > 0 and peak or 0 )
1334
1335 if start > peak or peak > stop then
1336
1337 elseif start < 0 and stop > 0 and peak ~ = 0 then
1338
1339 elseif peak = = 0 then
1340
1341 elseif f < start or f > stop then
1342
1343 s = 0
1344 break
1345 elseif f < peak then
1346
1347 s = s * ( f - start ) / ( peak - start )
1348 elseif f > peak then
1349 s = s * ( stop - f ) / ( stop - peak )
1350 else
1351
1352 end
1353 end
1354 if s = = 0 then
1355 if name then
1356 report ( " no deltas applied for glyph %a " , name )
1357 end
1358 else
1359 deltas [ # deltas + 1 ] = {
1360 factor = s ,
1361 points = points ,
1362 xvalues = xvalues ,
1363 yvalues = yvalues ,
1364 }
1365 end
1366 end
1367 if shape . type = = " glyph " then
1368 applyaxis ( glyph , shape , deltas , dowidth )
1369 else
1370
1371
1372 shape . deltas = deltas
1373 end
1374 end
1375 end
1376 startoffset = nextoffset
1377 end
1378 end
1379end
1380 |