1 // -*- related-file-name: "../include/efont/ttfcs.hh" -*-
2 
3 /* ttfcs.{cc,hh} -- TrueType "charstring" emulation
4  *
5  * Copyright (c) 2006-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/ttfcs.hh>
20 #include <efont/ttfhead.hh>
21 #include <efont/t1csgen.hh>
22 #include <efont/otfpost.hh>
23 #include <efont/otfcmap.hh>
24 #include <lcdf/hashmap.hh>
25 #include <algorithm>
26 namespace Efont {
27 typedef OpenType::Glyph Glyph;
28 
TrueTypeBoundsCharstringProgram(const OpenType::Font * otf)29 TrueTypeBoundsCharstringProgram::TrueTypeBoundsCharstringProgram(const OpenType::Font* otf)
30     : CharstringProgram(otf->units_per_em()),
31       _otf(otf), _nglyphs(-1), _loca_long(false),
32       _loca(otf->table("loca")), _glyf(otf->table("glyf")),
33       _hmtx(otf->table("hmtx")), _got_glyph_names(false), _got_unicodes(false)
34 {
35     OpenType::Data maxp(otf->table("maxp"));
36     if (maxp.length() >= 6)
37         _nglyphs = maxp.u16(4);
38 
39     OpenType::Head head(otf->table("head"), 0);
40     if (head.ok())
41         _loca_long = head.index_to_loc_format() != 0;
42     if (_loca_long)
43         _loca.align_long();
44     int loca_onesize = (_loca_long ? 4 : 2);
45     if (_nglyphs >= _loca.length() / loca_onesize)
46         _nglyphs = (_loca.length() / loca_onesize) - 1;
47 
48     // horizontal metrics
49     OpenType::Data hhea(_otf->table("hhea"));
50     // HHEA format:
51     // 0        Fixed   Table version number    0x00010000 for version 1.0.
52     // 4        FWORD   Ascender
53     // 6        FWORD   Descender
54     // 8        FWORD   LineGap
55     // 10       UFWORD  advanceWidthMax
56     // 12       FWORD   minLeftSideBearing
57     // 14       FWORD   minRightSideBearing
58     // 16       FWORD   xMaxExtent
59     // 18       SHORT   caretSlopeRise
60     // 20       SHORT   caretSlopeRun
61     // 22       SHORT   caretOffset
62     // 24       SHORT   (reserved)
63     // 26       SHORT   (reserved)
64     // 28       SHORT   (reserved)
65     // 30       SHORT   (reserved)
66     // 32       SHORT   metricDataFormat
67     // 34       USHORT  numberOfHMetrics
68     if (hhea.length() >= 36
69         && hhea.u32(0) == 0x10000)
70         _nhmtx = hhea.u16(34);
71     if (_nhmtx * 4 > _hmtx.length())
72         _nhmtx = _hmtx.length() / 4;
73 }
74 
~TrueTypeBoundsCharstringProgram()75 TrueTypeBoundsCharstringProgram::~TrueTypeBoundsCharstringProgram()
76 {
77     for (Charstring **cs = _charstrings.begin(); cs < _charstrings.end(); cs++)
78         delete *cs;
79 }
80 
font_matrix(double matrix[6]) const81 void TrueTypeBoundsCharstringProgram::font_matrix(double matrix[6]) const {
82     matrix[0] = matrix[3] = 1.0 / _otf->units_per_em();
83     matrix[1] = matrix[2] = matrix[4] = matrix[5] = 0;
84 }
85 
86 int
nglyphs() const87 TrueTypeBoundsCharstringProgram::nglyphs() const
88 {
89     return _nglyphs;
90 }
91 
92 PermString
glyph_name(int gi) const93 TrueTypeBoundsCharstringProgram::glyph_name(int gi) const
94 {
95     // generate glyph names based on what pdftex can understand
96     if (gi == 0)
97         return PermString(".notdef");
98 
99     // try 'post' table glyph names
100     if (!_got_glyph_names) {
101         OpenType::Post post(_otf->table("post"));
102         if (post.ok())
103             post.glyph_names(_glyph_names);
104         HashMap<PermString, int> name2glyph(-1);
105         // some 'post' tables are bogus, reject multiply-encoded names
106         for (int gi = 0; gi < _glyph_names.size(); ++gi) {
107             int& xgi = name2glyph.find_force(_glyph_names[gi]);
108             if (xgi == -1)
109                 xgi = gi;
110             else if (xgi == 0)
111                 _glyph_names[gi] = PermString();
112             else
113                 _glyph_names[gi] = _glyph_names[xgi] = PermString();
114         }
115         _got_glyph_names = true;
116     }
117     if (gi >= 0 && gi < _glyph_names.size() && _glyph_names[gi])
118         return _glyph_names[gi];
119 
120     // try 'uniXXXX' names
121     if (!_got_unicodes) {
122         OpenType::Cmap cmap(_otf->table("cmap"));
123         if (cmap.ok()) {
124             Vector<std::pair<uint32_t, Glyph> > ugp;
125             cmap.unmap_all(ugp);
126             std::sort(ugp.begin(), ugp.end());
127             for (Vector<std::pair<uint32_t, Glyph> >::iterator it = ugp.begin();
128                  it != ugp.end(); ) {
129                 Vector<std::pair<uint32_t, Glyph> >::iterator nit = it + 1;
130                 // ignore code points with multiple glyph mappings
131                 if (nit == ugp.end() || nit->first != it->first) {
132                     if (it->second >= _unicodes.size())
133                         _unicodes.resize(it->second + 1, 0);
134                     if (!_unicodes[it->second])
135                         _unicodes[it->second] = it->first;
136                 } else
137                     while (nit != ugp.end() && nit->first == it->first)
138                         ++nit;
139                 it = nit;
140             }
141         }
142         _got_unicodes = true;
143     }
144 
145     if (gi >= 0 && gi < _unicodes.size() && _unicodes[gi] > 0 && _unicodes[gi] <= 0xFFFF) {
146         char buf[10];
147         sprintf(buf, "uni%04X", _unicodes[gi]);
148         return PermString(buf);
149     } else
150         return permprintf("index%d", gi);
151 }
152 
153 void
glyph_names(Vector<PermString> & gn) const154 TrueTypeBoundsCharstringProgram::glyph_names(Vector<PermString> &gn) const
155 {
156     gn.clear();
157     for (int gi = 0; gi < _nglyphs; gi++)
158         gn.push_back(glyph_name(gi));
159 }
160 
161 Charstring *
glyph(int gi) const162 TrueTypeBoundsCharstringProgram::glyph(int gi) const
163 {
164     if (gi < 0 || gi >= _nglyphs)
165         return 0;
166     if (_charstrings.size() <= gi)
167         _charstrings.resize(gi + 1, (Charstring *) 0);
168     if (!_charstrings[gi]) {
169         // calculate glyf offsets
170         uint32_t offset, end_offset;
171         if (_loca_long) {
172             offset = _loca.u32(gi * 4);
173             end_offset = _loca.u32(gi * 4 + 4);
174         } else {
175             offset = _loca.u16(gi * 2) * 2;
176             end_offset = _loca.u16(gi * 2 + 2) * 2;
177         }
178 
179         // fetch bounding box from glyf
180         int ncontours, xmin, ymin, xmax, ymax;
181         if (offset != end_offset) {
182             if (offset > end_offset || offset + 10 > end_offset
183                 || end_offset > (uint32_t) _glyf.length())
184                 return 0;
185 
186             ncontours = _glyf.s16(offset);
187             xmin = _glyf.s16(offset + 2);
188             ymin = _glyf.s16(offset + 4);
189             xmax = _glyf.s16(offset + 6);
190             ymax = _glyf.s16(offset + 8);
191         } else
192             ncontours = xmin = ymin = xmax = ymax = 0;
193 
194         // fetch horizontal metrics
195         int advance_width, lsb;
196         if (gi >= _nhmtx) {
197             advance_width = (_nhmtx ? _hmtx.u16((_nhmtx - 1) * 4) : 0);
198             int hmtx_offset = _nhmtx * 4 + (gi - _nhmtx) * 2;
199             lsb = (hmtx_offset + 2 <= _hmtx.length() ? _hmtx.s16(hmtx_offset) : 0);
200         } else {
201             advance_width = _hmtx.u16(gi * 4);
202             lsb = _hmtx.s16(gi * 4 + 2);
203         }
204 
205         // make charstring
206         Type1CharstringGen gen;
207         if (ncontours == 0) {
208             gen.gen_number(0, 'X');
209             gen.gen_number(advance_width);
210             gen.gen_command(Charstring::cHsbw);
211         } else {
212             gen.gen_number(lsb, 'X');
213             gen.gen_number(advance_width);
214             gen.gen_command(Charstring::cHsbw);
215             gen.gen_moveto(Point(xmin, ymin), false, false);
216             if (xmax != xmin || ymax == ymin)
217                 gen.gen_number(xmax - xmin, 'x');
218             if (ymax != ymin)
219                 gen.gen_number(ymax - ymin, 'y');
220             gen.gen_command(ymax == ymin ? Charstring::cHlineto
221                             : (xmax == xmin ? Charstring::cVlineto
222                                : Charstring::cRlineto));
223             gen.gen_command(Charstring::cClosepath);
224         }
225         gen.gen_command(Charstring::cEndchar);
226 
227         _charstrings[gi] = gen.output();
228     }
229     return _charstrings[gi];
230 }
231 
232 }
233