1 // -*- related-file-name: "../include/efont/afmw.hh" -*-
2
3 /* afmw.{cc,hh} -- Adobe Font Metrics writing
4 *
5 * Copyright (c) 1998-2019 Eddie Kohler
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version. This program is distributed in the hope that it will be
11 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
13 * Public License for more details.
14 */
15
16 #ifdef HAVE_CONFIG_H
17 # include <config.h>
18 #endif
19 #include <efont/afmw.hh>
20 #include <efont/t1cs.hh> /* for KNOWN() */
21 namespace Efont {
22
AfmWriter(Metrics * m,FILE * f)23 AfmWriter::AfmWriter(Metrics *m, FILE *f)
24 : _m(m), _afm_xt((AfmMetricsXt *)m->find_xt("AFM")), _f(f)
25 {
26 }
27
28 void
write(Metrics * m,FILE * f)29 AfmWriter::write(Metrics *m, FILE *f)
30 {
31 AfmWriter w(m, f);
32 w.write();
33 }
34
35
36 void
write()37 AfmWriter::write()
38 {
39 _m->pair_program()->unreverse();
40 _m->pair_program()->optimize();
41
42 fprintf(_f, "StartFontMetrics 4.1\n");
43 if (_afm_xt)
44 for (int i = 0; i < _afm_xt->opening_comments.size(); i++)
45 fprintf(_f, "Comment %s\n", _afm_xt->opening_comments[i].c_str());
46
47 write_prologue();
48
49 fprintf(_f, "StartCharMetrics %d\n", _m->nglyphs());
50
51 GlyphIndex gi;
52 for (int i = 0; i < 256; i++) //FIXME
53 if ((gi = _m->find_code(i)) >= 0)
54 write_char_metric_data(gi, i);
55 for (gi = 0; gi < _m->nglyphs(); gi++)
56 if (_m->code(gi) == -1)
57 write_char_metric_data(gi, -1);
58
59 fprintf(_f, "EndCharMetrics\n");
60
61 write_kerns();
62
63 fprintf(_f, "EndFontMetrics\n");
64 }
65
66
67 void
write_prologue() const68 AfmWriter::write_prologue() const
69 {
70 if (_m->font_name())
71 fprintf(_f, "FontName %s\n", _m->font_name().c_str());
72 else
73 fprintf(_f, "FontName No-Font-Name-Given\n");
74
75 if (_m->full_name())
76 fprintf(_f, "FullName %s\n", _m->full_name().c_str());
77 if (_m->family())
78 fprintf(_f, "FamilyName %s\n", _m->family().c_str());
79 if (_m->weight())
80 fprintf(_f, "Weight %s\n", _m->weight().c_str());
81
82 if (KNOWN(fd( fdItalicAngle )))
83 fprintf(_f, "ItalicAngle %.8g\n", fd( fdItalicAngle ));
84
85 fprintf(_f, "FontBBox %.8g %.8g %.8g %.8g\n",
86 fd( fdFontBBllx ), fd( fdFontBBlly ),
87 fd( fdFontBBurx ), fd( fdFontBBury ));
88
89 if (KNOWN(fd( fdUnderlinePosition )))
90 fprintf(_f, "UnderlinePosition %.8g\n", fd( fdUnderlinePosition ));
91 if (KNOWN(fd( fdUnderlineThickness )))
92 fprintf(_f, "UnderlineThickness %.8g\n", fd( fdUnderlineThickness ));
93
94 if (_m->version())
95 fprintf(_f, "Version %s\n", _m->version().c_str());
96 if (_afm_xt && _afm_xt->notice)
97 fprintf(_f, "Notice %s\n", _afm_xt->notice.c_str());
98
99 if (_afm_xt && _afm_xt->encoding_scheme)
100 fprintf(_f, "EncodingScheme %s\n", _afm_xt->encoding_scheme.c_str());
101
102 if (KNOWN(fd( fdCapHeight )))
103 fprintf(_f, "CapHeight %.8g\n", fd( fdCapHeight ));
104 if (KNOWN(fd( fdXHeight )))
105 fprintf(_f, "XHeight %.8g\n", fd( fdXHeight ));
106 if (KNOWN(fd( fdAscender )))
107 fprintf(_f, "Ascender %.8g\n", fd( fdAscender ));
108 if (KNOWN(fd( fdDescender )))
109 fprintf(_f, "Descender %.8g\n", fd( fdDescender ));
110 if (KNOWN(fd( fdStdHW )))
111 fprintf(_f, "StdHW %.8g\n", fd( fdStdHW ));
112 if (KNOWN(fd( fdStdVW )))
113 fprintf(_f, "StdVW %.8g\n", fd( fdStdVW ));
114 }
115
116
117 void
write_char_metric_data(GlyphIndex gi,int e) const118 AfmWriter::write_char_metric_data(GlyphIndex gi, int e) const
119 {
120 if (e >= -1 && e < 256)
121 fprintf(_f, "C %d ;", e);
122 else
123 fprintf(_f, "CH <%04X> ;", e);
124
125 double w = _m->wd(gi);
126 if (KNOWN(w))
127 fprintf(_f, " WX %.8g ;", w);
128 else
129 w = 0;
130
131 fprintf(_f, " N %s ;", _m->name(gi).c_str());
132
133 if (KNOWN(_m->lf(gi)))
134 fprintf(_f, " B %.8g %.8g %.8g %.8g ;",
135 _m->lf(gi), _m->bt(gi), _m->rt(gi), _m->tp(gi));
136
137 // Run through the ligature/kern program to find ligatures.
138 PairProgram &pairp = *_m->pair_program();
139 PairOpIndex opi = pairp.find_left(gi);
140 while (opi >= 0) {
141 const PairOp &op = pairp.op(opi);
142 if (op.is_lig()) {
143 if (op.lig_kind() == opLigSimple)
144 fprintf(_f, " L %s %s ;",
145 _m->name( op.right() ).c_str(),
146 _m->name( op.result() ).c_str());
147 //else
148 //warning("strange ligature combination not supported by AFM");
149 }
150 opi = op.next_left();
151 }
152
153 fputc('\n', _f);
154 }
155
156
157 void
write_kerns() const158 AfmWriter::write_kerns() const
159 {
160 PairProgram &pairp = *_m->pair_program();
161
162 // Damn. First we have to count how many kerning pairs there are.
163 int numkerns = 0;
164 for (PairOpIndex opi = 0; opi < pairp.op_count(); opi++) {
165 const PairOp &op = pairp.op(opi);
166 if (op.is_kern() && _m->kv( op.value() ))
167 numkerns++;
168 }
169
170 if (numkerns == 0) return;
171
172 fprintf(_f, "StartKernData\n");
173 fprintf(_f, "StartKernPairs %d\n", numkerns);
174 for (GlyphIndex gi = 0; gi < _m->nglyphs(); gi++) {
175 PairOpIndex opi = pairp.find_left(gi);
176 while (opi >= 0) {
177 const PairOp &op = pairp.op(opi);
178 if (op.is_kern() && _m->kv( op.value() ))
179 fprintf(_f, "KPX %s %s %.8g\n",
180 _m->name( gi ).c_str(),
181 _m->name( op.right() ).c_str(),
182 _m->kv( op.value() ));
183 opi = op.next_left();
184 }
185 }
186 fprintf(_f, "EndKernPairs\n");
187 fprintf(_f, "EndKernData\n");
188 }
189
190 }
191