rfil 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/lib/rfil/font.rb ADDED
@@ -0,0 +1,722 @@
1
+ # font.rb - Implements Font. See that class for documentaton.
2
+ #--
3
+ # Last Change: Thu May 18 17:20:03 2006
4
+ #++
5
+ require 'set'
6
+
7
+ require 'rfil/helper'
8
+ require 'rfil/font/afm'
9
+ require 'rfil/font/truetype'
10
+ require 'tex/enc'
11
+ require 'tex/kpathsea'
12
+ require 'tex/tfm'
13
+ require 'tex/vf'
14
+ require 'rfil/rfi'
15
+
16
+
17
+
18
+ module RFIL # :nodoc:
19
+ class RFI # :nodoc:
20
+
21
+ # Main class to manipulate and combine font metrics. This is mostly a
22
+ # convenience class, if you don't want to do the boring stuff
23
+ # yourself. You can 'load' a font, manipulate the data and create a tfm
24
+ # and vf file. It is used in conjunction with FontCollection, a class
25
+ # that contains several Font objects (perhaps a font family).
26
+ # The Font class relys on TFM/VF to write out the tfm and vf files, on the
27
+ # subclasses of RFI, especially on RFI::Glyphlist that knows about a
28
+ # lot of things about the char metrics, ENC for handling the encoding
29
+ # information and, of course, FontMetric and its subclasses to read a
30
+ # font.
31
+ class Font
32
+ include TeX
33
+ def self.documented_as_accessor(*args) # :nodoc:
34
+ end
35
+
36
+ # lookup_meth
37
+ def self.lookup_meth(*args)
38
+ args.each do |arg|
39
+ define_method(arg) do
40
+ if @fontcollection
41
+ @fontcollection.instance_variable_get("@#{arg}")
42
+ else
43
+ instance_variable_get("@#{arg}")
44
+ end
45
+ end
46
+ define_method("#{arg}=") do |v|
47
+ instance_variable_set("@#{arg}", v)
48
+ end
49
+ end
50
+ end
51
+
52
+
53
+ lookup_meth :style, :write_vf
54
+
55
+ include Helper
56
+
57
+ RULE=[:setrule, 0.4, 0.4]
58
+
59
+ # The encoding that the PDF/PS expects (what is put before
60
+ # "ReEncodeFont" in the mapfile). If not set, use the setting from
61
+ # the fontcollection. You can specify at most one encoding. If you
62
+ # set it to an array of encodings, only the first item in the array
63
+ # will be used. The assignment to _mapenc_ can be an Enc object or a
64
+ # string that is a filename of the encoding. If unset, use all the
65
+ # encoding mentioned in #texenc. In this case, a one to one mapping
66
+ # will be done: 8r -> 8r, t1 -> t1 etc. (like the -T switch in
67
+ # afm2tfm).
68
+ documented_as_accessor :mapenc
69
+
70
+ # Array of encodings that TeX spits out. If it is not set, take
71
+ # the settings from the fontcollection.
72
+ documented_as_accessor :texenc
73
+
74
+ # The fontmetric of the default font
75
+ attr_accessor :defaultfm
76
+
77
+ # extend font with this factor
78
+ attr_accessor :efactor
79
+
80
+ # slantfactor
81
+ attr_accessor :slant
82
+
83
+ # Don't write out virtual fonts if write_vf is set to false here or
84
+ # in the fontcollection.
85
+ documented_as_accessor :write_vf
86
+
87
+ # sans, roman, typewriter
88
+ documented_as_accessor :style
89
+
90
+ # :regular, :bold, :black, :light
91
+ attr_accessor :weight
92
+
93
+ # :regular, :italic, :slanted, :smallcaps
94
+ attr_accessor :variant
95
+
96
+ # :dryrun, :verbose, see also fontcollection
97
+ attr_accessor :options
98
+
99
+ # all the loaded
100
+ attr_accessor :variants
101
+ # If fontcollection is supplied, we are now part as the
102
+ # fontcollection. You can set mapenc and texenc in the fontcollection
103
+ # and don't bother about it here. Settings in a Font object will
104
+ # override settings in the fontcollection.
105
+
106
+ def initialize (fontcollection=nil)
107
+ # we are part of a fontcollection
108
+ @fontcollection=fontcollection
109
+ # @defaultfm=FontMetric.new
110
+ @weight=:regular
111
+ @variant=:regular
112
+ @defaultfm=nil
113
+ @efactor=1.0
114
+ @slant=0.0
115
+ @capheight=nil
116
+ @write_vf=true
117
+ @texenc=nil
118
+ @mapenc=nil
119
+ @variants=[]
120
+ @style=nil
121
+ @dirs={}
122
+ @origsuffix="-orig"
123
+ @kpse=::TeX::Kpathsea.new
124
+ if fontcollection
125
+ unless @fontcollection.respond_to?(:register_font)
126
+ raise ArgumentError, "parameter does not look like a fontcollection"
127
+ end
128
+ @colnum=@fontcollection.register_font(self)
129
+ else
130
+ # the default dirs
131
+ set_dirs(Dir.getwd)
132
+ end
133
+ @options=Options.new(fontcollection)
134
+ end
135
+
136
+ # hook run after font has been loaded by load_variant
137
+ def after_load_hook
138
+ end
139
+ # Read a font(metric file). Return a number that identifies the font.
140
+ # The first font read is the default font.
141
+ def load_variant(fontname)
142
+ fm=nil
143
+
144
+ if fontname.instance_of? String
145
+ if File.exists?(fontname)
146
+ case File.extname(fontname)
147
+ when ".afm"
148
+ fm=RFIL::Font::AFM.new
149
+ when ".ttf"
150
+ fm=RFIL::Font::TrueType.new
151
+ else
152
+ raise ArgumentError, "Unknown filetype: #{File.basename(fontname)}"
153
+ end
154
+ else
155
+ # let us guess the inputfile
156
+ %w( .afm .ttf ).each { |ext|
157
+ if File.exists?(fontname+ext)
158
+ fontname += ext
159
+ case ext
160
+ when ".afm"
161
+ fm=RFIL::Font::AFM.new
162
+ when ".ttf"
163
+ fm=RFIL::Font::TrueType.new
164
+ end
165
+ break
166
+ end
167
+ }
168
+ end
169
+ raise Errno::ENOENT,"Font not found: #{fontname}" unless fm
170
+ # We need more TeX-specific classes:
171
+ fm.glyph_class=RFIL::RFI::Char
172
+ # fm.glyph_class=::Font::Glyph
173
+ fm.chars=RFIL::RFI::Glyphlist.new
174
+ fm.read(fontname)
175
+ raise ScriptError, "Fontname is not set" unless fm.name
176
+ elsif fontname.respond_to? :charwd
177
+ # some kind of font metric
178
+ fm=fontname
179
+ end
180
+ class << fm
181
+ # scalefactor of font (1=don't scale)
182
+ attr_accessor :fontat
183
+
184
+ # auxiliary attribute to store the name of the 'original' font
185
+ attr_accessor :mapto
186
+ end
187
+
188
+
189
+ @variants.push(fm)
190
+ fontnumber=@variants.size - 1
191
+
192
+ # the first font loaded is the default font
193
+ if fontnumber == 0
194
+ @defaultfm = fm
195
+ end
196
+
197
+ fm.chars.each { |name,chardata|
198
+ chardata.fontnumber=fontnumber
199
+ }
200
+
201
+ fm.chars.fix_height(fm.xheight)
202
+ fm.fontat=1 # default scale factor
203
+ after_load_hook
204
+ fontnumber
205
+ end # load_variant
206
+
207
+
208
+ # change the metrics (and glyphs) of the default font so that
209
+ # uppercase variants are mapped onto the lowercase variants.
210
+ def fake_caps(fontnumber,capheight)
211
+ raise ScriptError, "no font loaded" unless @defaultfm
212
+ # first, make a list of uppercase and lowercase glyphs
213
+ @defaultfm.chars.update_uc_lc_list
214
+ @capheight=capheight
215
+ v=@variants[fontnumber]
216
+ v.fontat=capheight
217
+ v.chars.fake_caps(capheight)
218
+ end
219
+
220
+
221
+ # Return tfm object for that font. _enc_ is the encoding of the
222
+ # tfm file, which must be an ENC object. Ligature and kerning
223
+ # information is put into the tfm file unless <tt>:noligs</tt> is
224
+ # set to true in the opts.
225
+ def to_tfm(enc,opts={})
226
+ tfm=::TeX::TFM.new
227
+ tfm.fontfamily=@defaultfm.familyname
228
+ tfm.codingscheme=enc.encname
229
+ tfm.designsize=10.0
230
+
231
+ tfm.params[1]=(@slant - @efactor * Math::tan(@defaultfm.italicangle * Math::PI / 180.0)) / 1000.0
232
+
233
+ tfm.params[2]=(transform(@defaultfm.space,0)) / 1000.0
234
+ tfm.params[3]=(@defaultfm.isfixedpitch ? 0 : transform(0.3,0))
235
+ tfm.params[4]=(@defaultfm.isfixedpitch ? 0 : transform(0.1,0))
236
+ tfm.params[5]=@defaultfm.xheight / 1000.0
237
+ tfm.params[6]=transform(1.0,0)
238
+
239
+ charhash=enc.glyph_index.dup
240
+
241
+ enc.each_with_index{ |char,i|
242
+ next if char==".notdef"
243
+
244
+ thischar=@defaultfm.chars[char]
245
+ next unless thischar
246
+
247
+ # ignore those chars we have already encountered
248
+ next unless charhash.has_key?(char)
249
+
250
+ thischar.efactor=@efactor
251
+ thischar.slant=@slant
252
+
253
+ c={}
254
+ charhash[char].each { |slot|
255
+ tfm.chars[slot]=c
256
+ }
257
+ charhash.delete(char)
258
+
259
+ [:charwd, :charht, :chardp, :charic].each { |sym|
260
+ c[sym]=thischar.send(sym) / 1000.0
261
+ }
262
+ }
263
+ if opts[:noligs] != true
264
+ tfm_lig(tfm,enc)
265
+ end
266
+
267
+ return tfm
268
+ end
269
+
270
+ # Return vf object for that font. _mapenc_l_ and _texenc_ must be an
271
+ # ENC object. _mapenc_l_ is the destination encoding (of the fonts
272
+ # in the mapfile) and _texenc_ is is the encoding of the resulting
273
+ # tfm file. They may be the same.
274
+ def to_vf(mapenc_l,texenc)
275
+ raise ArgumentError, "mapenc must be an ENC object" unless mapenc_l.respond_to? :encname
276
+ raise ArgumentError, "texenc must be an ENC object" unless texenc.respond_to? :encname
277
+ vf=::TeX::VF.new
278
+ vf.vtitle="Installed with rfi library"
279
+ vf.fontfamily=@defaultfm.familyname
280
+ vf.codingscheme= if mapenc_l.encname != texenc.encname
281
+ mapenc_l.encname + " + " + texenc.encname
282
+ else
283
+ mapenc_l.encname
284
+ end
285
+ vf.designsize=10.0
286
+ fm=@defaultfm
287
+
288
+ vf.params[1]=(@slant - @efactor * Math::tan(@defaultfm.italicangle * Math::PI / 180.0)) / 1000.0
289
+ vf.params[2]=(transform(@defaultfm.space,0)) / 1000.0
290
+ vf.params[3]=(@defaultfm.isfixedpitch ? 0 : transform(0.3,0))
291
+ vf.params[4]=(@defaultfm.isfixedpitch ? 0 : transform(0.1,0))
292
+ vf.params[5]=@defaultfm.xheight / 1000.0
293
+ vf.params[6]=transform(1,0)
294
+ vf.params[7]==fm.isfixedpitch ? fm.space : transform(0.111,0)
295
+
296
+ # mapfont
297
+ find_used_fonts.each_with_index { |fontnumber,i|
298
+ fl=vf.fontlist[fontnumber]={}
299
+ tfm=fl[:tfm]=::TeX::TFM.new
300
+ tfm.tfmpathname=map_fontname(mapenc_l,fontnumber)
301
+ fl[:scale]=@variants[fontnumber].fontat
302
+ }
303
+
304
+ charhash=texenc.glyph_index.dup
305
+ texenc.each_with_index { |char,i|
306
+ next if char==".notdef"
307
+
308
+ thischar=@defaultfm.chars[char]
309
+ next unless thischar
310
+
311
+ # ignore those chars we have already encountered
312
+ next unless charhash.has_key?(char)
313
+
314
+ thischar.efactor=@efactor
315
+ thischar.slant=@slant
316
+
317
+ c={}
318
+ charhash[char].each { |slot|
319
+ vf.chars[slot]=c
320
+ }
321
+ charhash.delete(char)
322
+ c[:dvi]=dvi=[]
323
+
324
+ if thischar.fontnumber > 0
325
+ dvi << [:selectfont,thischar.fontnumber]
326
+ end
327
+
328
+ if thischar.pcc_data
329
+ thischar.pcc_data.each { |pcc|
330
+ if mapenc_l.glyph_index[pcc[0]]
331
+ dvi << [:setchar,mapenc_l.glyph_index[pcc[0]].min]
332
+ else
333
+ dvi << RULE
334
+ end
335
+ }
336
+ elsif thischar.mapto
337
+ if mapenc_l.glyph_index[thischar.mapto]
338
+ if mapenc_l.glyph_index[thischar.mapto]
339
+ dvi << [:setchar, mapenc_l.glyph_index[thischar.mapto].min]
340
+ else
341
+ dvi << RULE
342
+ end
343
+ else
344
+ dvi << [:special, "unencoded glyph '#{char}'"]
345
+ dvi << RULE
346
+ end
347
+ elsif mapenc_l.glyph_index[char]
348
+ dvi << [:setchar, mapenc_l.glyph_index[char].min]
349
+ else
350
+ dvi << RULE
351
+ end
352
+ [:charwd, :charht, :chardp, :charic].each { |sym|
353
+ c[sym]=thischar.send(sym) / 1000.0
354
+ }
355
+ }
356
+ tfm_lig(vf,texenc)
357
+
358
+ return vf
359
+ end
360
+
361
+
362
+ # Todo: document and test!
363
+ def apply_ligkern_instructions(what)
364
+ @defaultfm.chars.apply_ligkern_instructions(what)
365
+ end
366
+
367
+ # Return a string or an array of strings that should be put in a mapfile.
368
+ def maplines()
369
+ # "normally" (afm2tfm)
370
+ # savorg__ Savoy-Regular " mapenc ReEncodeFont " <savorg__ <mapenc.enc
371
+
372
+ # enc-fontname[-variant]*.tfm
373
+
374
+ # or without the "ReEncodeFont" (check!)
375
+
376
+
377
+ # we default to ase (Adobe Standard Encoding), on your TeX system
378
+ # as 8a.enc
379
+
380
+ # if mapenc (the encoding TeX writes to the dvi file) is not set
381
+ texenc_loc = texenc
382
+ unless texenc_loc
383
+ f=@kpse.open_file("8a.enc","enc")
384
+ texenc_loc=[ENC.new(f)]
385
+ f.close
386
+ end
387
+ ret=[]
388
+ encodings=Set.new
389
+ texenc.each { |te|
390
+ encodings.add mapenc ? mapenc : te
391
+ }
392
+ fontsused=find_used_fonts
393
+ encodings.each { |te|
394
+ fontsused.each { |f|
395
+ str=map_fontname(te,f)
396
+ str << " #{@variants[f].fontname} "
397
+ instr=[]
398
+ if @slant != 0.0
399
+ instr << "#@slant SlantFont"
400
+ end
401
+ if @efactor != 1.0
402
+ instr << "#@efactor ExtendFont"
403
+ end
404
+ unless te.filename == "8a.enc"
405
+ instr << "#{te.encname} ReEncodeFont"
406
+ end
407
+
408
+ str << "\"" << instr.join(" ") << "\"" if instr.size > 0
409
+ unless te.filename == "8a.enc"
410
+ str << " <#{te.filename}"
411
+ end
412
+ str << " <#{@variants[f].fontfilename}"
413
+ str << "\n"
414
+ ret.push str
415
+ }
416
+ }
417
+ # FIXME: remove duplicate lines in a more sensible way
418
+ # no fontname (first entry) should appear twice!
419
+ ret.uniq
420
+ end
421
+
422
+ # Creates all the necessary files to use the font. This is mainly a
423
+ # shortcut if you are too lazy to program. _opts_:
424
+ # [:dryrun] true/false
425
+ # [:verbose] true/false
426
+ # [:mapfile] true/false
427
+
428
+ def write_files(opts={})
429
+
430
+
431
+ tfmdir=get_dir(:tfm); ensure_dir(tfmdir)
432
+ vfdir= get_dir(:vf) ; ensure_dir(vfdir)
433
+ unless opts[:mapfile]==false
434
+ mapdir=get_dir(:map); ensure_dir(mapdir)
435
+ end
436
+
437
+ encodings=Set.new
438
+ texenc.each { |te|
439
+ encodings.add mapenc ? mapenc : te
440
+ }
441
+ encodings.each { |enc|
442
+ find_used_fonts.each { |var|
443
+ tfmfilename=File.join(tfmdir,map_fontname(enc,var) + ".tfm")
444
+
445
+ if options[:verbose]==true
446
+ puts "tfm: writing tfm: #{tfmfilename}"
447
+ end
448
+ unless options[:dryrun]==true
449
+ tfm=to_tfm(enc)
450
+ tfm.tfmpathname=tfmfilename
451
+ tfm.save(true)
452
+ end
453
+ }
454
+ }
455
+
456
+ if write_vf
457
+ encodings=Set.new
458
+ texenc.each { |te|
459
+ encodings.add mapenc ? mapenc : te
460
+ }
461
+ texenc.each { |te|
462
+ outenc = mapenc ? mapenc : te
463
+ vffilename= File.join(vfdir, tex_fontname(te) + ".vf")
464
+ tfmfilename=File.join(tfmdir,tex_fontname(te) + ".tfm")
465
+ if options[:verbose]==true
466
+ puts "vf: writing tfm: #{tfmfilename}"
467
+ puts "vf: writing vf: #{vffilename}"
468
+ end
469
+ unless options[:dryrun]==true
470
+ vf=to_vf(outenc,te)
471
+ vf.tfmpathname=tfmfilename
472
+ vf.vfpathname=vffilename
473
+ vf.save(true)
474
+ end
475
+ }
476
+ end
477
+
478
+ unless opts[:mapfile]==false
479
+ # mapfile
480
+ if options[:verbose]==true
481
+ puts "writing #{mapfilename}"
482
+ end
483
+ unless options[:dryrun]==true
484
+ File.open(mapfilename,"w") { |f|
485
+ f << maplines
486
+ }
487
+ end
488
+ end
489
+ end
490
+
491
+ # Return a directory where files of type _type_ will be placed in.
492
+ # Default to current working directory.
493
+ def get_dir(type)
494
+ if @dirs.has_key?(type)
495
+ @dirs[type]
496
+ elsif @fontcollection and @fontcollection.dirs.has_key?(type)
497
+ @fontcollection.dirs[type]
498
+ else
499
+ Dir.getwd
500
+ end
501
+ end
502
+
503
+ def mapenc # :nodoc:
504
+ return nil if @mapenc == :none
505
+ if @mapenc==nil and @fontcollection
506
+ @fontcollection.mapenc
507
+ else
508
+ @mapenc
509
+ end
510
+ end
511
+ def mapenc=(enc) # :nodoc:
512
+ set_mapenc(enc)
513
+ end
514
+
515
+ def texenc # :nodoc:
516
+ if @texenc
517
+ @texenc
518
+ else
519
+ # @texenc not set
520
+ if @fontcollection
521
+ @fontcollection.texenc
522
+ else
523
+ ret=nil
524
+ @kpse.open_file("8a.enc","enc") { |f|
525
+ ret = [ENC.new(f)]
526
+ }
527
+ # puts "returning #{ret}"
528
+ return ret
529
+ end
530
+ end
531
+ end
532
+ def texenc=(enc) # :nodoc:
533
+ @texenc=[]
534
+ if enc
535
+ set_encarray(enc,@texenc)
536
+ end
537
+ end
538
+
539
+ # Return the full path to the mapfile.
540
+ def mapfilename
541
+ File.join(get_dir(:map),@defaultfm.name + ".map")
542
+ end
543
+
544
+
545
+
546
+ # Copy glyphs from one font to the default font. _fontnumber_ is the
547
+ # number that is returned from load_variant, _glyphlist_ is whatever
548
+ # you want to copy. Overwrites existing chars. _opts_ is one of:
549
+ # [:ligkern] copy the ligature and kerning information with the glyphs stated in glyphlist. This will remove all related existing ligature and kerning information the default font.
550
+ # *needs testing*
551
+ def copy(fontnumber,glyphlist,opts={})
552
+ tocopy=[]
553
+ case glyphlist
554
+ when Symbol
555
+ tocopy=@defaultfm.chars.get_glyphlist(glyphlist)
556
+ when Array
557
+ tocopy=glyphlist
558
+ end
559
+
560
+ tocopy.each { |glyphname|
561
+ @defaultfm.chars[glyphname]=@variants[fontnumber].chars[glyphname]
562
+ @defaultfm.chars[glyphname].fontnumber=fontnumber
563
+ }
564
+ if opts[:ligkern]==true
565
+ # assume: copying lowercase letters.
566
+ # we need to copy *all* lowercase -> * data and replace all
567
+ # we need to remove all uppercase -> lowercase data first
568
+ # we need to copy all uppercase -> lowercase data
569
+ @variants[fontnumber].chars.each { |glyphname,data|
570
+ if tocopy.member?(glyphname)
571
+ #puts "font#copy: using kern_data for #{glyphname}"
572
+ @defaultfm.chars[glyphname].kern_data=data.kern_data.dup
573
+ else
574
+ # delete all references to the 'tocopy'
575
+ @defaultfm.chars[glyphname].kern_data.each { |destchar,kern|
576
+ if tocopy.member?(destchar)
577
+ #puts "font#copy: removing kern_data for #{glyphname}->#{destchar}"
578
+ @defaultfm.chars[glyphname].kern_data.delete(destchar)
579
+ end
580
+ }
581
+ data.kern_data.each { |destchar,kern|
582
+ if tocopy.member?(destchar)
583
+ @defaultfm.chars[glyphname].kern_data[destchar]=kern
584
+ end
585
+ }
586
+ end
587
+ }
588
+ end
589
+ end # copy
590
+
591
+ # Return an array with all used fontnumbers loaded with
592
+ # load_variant. If, for example, fontnubmer 0 and 3 are used,
593
+ # find_used_fonts would return [0,3].
594
+ def find_used_fonts
595
+ fonts=Set.new
596
+ @defaultfm.chars.each{ |glyph,data|
597
+ fonts.add(data.fontnumber)
598
+ }
599
+ fonts.to_a.sort
600
+ end
601
+
602
+
603
+ # Return the name of the font in the mapline. If we don't write
604
+ # virtual fonts, this is the name of the tfm file written. If we
605
+ # write vf's, than this is the name used in the mapfont section of
606
+ # the virtual font as well as the name of the tfm file, but both
607
+ # with some marker that this font 'should' not be used directly.
608
+ def map_fontname (texenc,varnumber=0,opts={})
609
+ mapenc_loc=mapenc
610
+ suffix=""
611
+ suffix << @origsuffix if write_vf
612
+ if mapenc_loc
613
+ # use the one in mapenc_loc
614
+ construct_fontname(mapenc,varnumber) + suffix
615
+ else
616
+ construct_fontname(texenc,varnumber) + suffix
617
+ end
618
+ end
619
+
620
+ # Return the name
621
+ def tex_fontname (encoding)
622
+ tf=construct_fontname(encoding)
623
+ tf << "-capitalized-#{(@capheight*1000).round}" if @capheight
624
+ tf
625
+ end
626
+ def guess_weight_variant
627
+ fm=@defaultfm
628
+ # fm[:smallcaps] = false
629
+ # fm[:expert] = false
630
+ [fm.fontname,fm.familyname,fm.weight].each { |fontinfo|
631
+ case fontinfo
632
+ when /italic/i
633
+ @variant=:italic
634
+ when /oblique/i
635
+ @variant=:italic
636
+ when /bold/i
637
+ @weight=:bold
638
+ when /smcaps/i
639
+ @variant=:smallcaps
640
+ # when /expert/i
641
+ # f[:expert] = true
642
+ # puts "expert"
643
+ end
644
+ }
645
+ end
646
+
647
+ #######
648
+ private
649
+ #######
650
+ def tfm_lig(tfm,enc)
651
+ charhash=enc.glyph_index.dup
652
+
653
+ enc.each_with_index { |char,i|
654
+ next if char==".notdef"
655
+
656
+ thischar=@defaultfm.chars[char]
657
+ next unless thischar
658
+
659
+ # ignore those chars we have already encountered
660
+ next unless charhash.has_key?(char)
661
+ lk=[]
662
+
663
+ thischar.lig_data.each_value { |lig|
664
+ if (enc.glyph_index.has_key? lig.right) and
665
+ (enc.glyph_index.has_key? lig.result)
666
+ # lig is like "hyphen ..." but needs to be in a format like
667
+ # "45 .."
668
+ lk += lig.to_tfminstr(enc)
669
+ end
670
+ }
671
+ thischar.kern_data.each { |dest,kern|
672
+ if (enc.glyph_index.has_key? dest)
673
+ enc.glyph_index[dest].each { |slot|
674
+ lk << [:krn, slot,(kern[0]*@efactor)/1000.0]
675
+ }
676
+ end
677
+ }
678
+ next if lk.size==0
679
+ instrnum = tfm.lig_kern.size
680
+ tfm.lig_kern << lk
681
+
682
+ charhash[char].each { |slot|
683
+ c=tfm.chars[slot] ||= {}
684
+ c[:lig_kern]=instrnum
685
+ }
686
+ charhash.delete(char)
687
+ }
688
+ return tfm
689
+ end
690
+
691
+ def construct_fontname(encoding,varnumber=0)
692
+ encodingname=if String === encoding
693
+ encoding
694
+ else
695
+ if encoding.filename
696
+ encoding.filename.chomp(".enc").downcase
697
+ else
698
+ encoding.encname
699
+ end
700
+ end
701
+
702
+ fontname=@variants[varnumber].name
703
+ # default
704
+ tf=if encodingname == "8a"
705
+ "#{fontname}"
706
+ else
707
+ "#{encodingname}-#{fontname}"
708
+ end
709
+ tf << "-slanted-#{(@slant*100).round}" if @slant != 0.0
710
+ tf << "-extended-#{(@efactor*100).round}" if @efactor != 1.0
711
+
712
+ tf
713
+
714
+ end
715
+
716
+ def transform (x,y)
717
+ @efactor * x + @slant * y
718
+ end
719
+
720
+ end # class Font
721
+ end # class RFI
722
+ end #module RFIL