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/COPYING +340 -0
- data/README +77 -0
- data/examples/afm2tfm.rb +204 -0
- data/examples/afminfo +305 -0
- data/examples/encodingtable +65 -0
- data/examples/pldiff +295 -0
- data/examples/plinfo +108 -0
- data/examples/rfii +257 -0
- data/examples/rfont +188 -0
- data/lib/rfil/font.rb +722 -0
- data/lib/rfil/font/afm.rb +414 -0
- data/lib/rfil/font/glyph.rb +198 -0
- data/lib/rfil/font/metric.rb +135 -0
- data/lib/rfil/font/truetype.rb +35 -0
- data/lib/rfil/fontcollection.rb +182 -0
- data/lib/rfil/helper.rb +155 -0
- data/lib/rfil/rfi.rb +472 -0
- data/lib/rfil/rfi_plugin_context.rb +90 -0
- data/lib/rfil/rfi_plugin_latex.rb +95 -0
- data/lib/rfil/version.rb +3 -0
- data/lib/tex/enc.rb +223 -0
- data/lib/tex/kpathsea.rb +63 -0
- data/lib/tex/tfm.rb +1198 -0
- data/lib/tex/vf.rb +846 -0
- metadata +86 -0
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
|