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