1 //========================================================================
2 //
3 // WebFont.cc
4 //
5 // Copyright 2019 Glyph & Cog, LLC
6 //
7 //========================================================================
8
9 #include <aconf.h>
10
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
13 #endif
14
15 #include "gmem.h"
16 #include "gmempp.h"
17 #include "GHash.h"
18 #include "FoFiTrueType.h"
19 #include "FoFiType1C.h"
20 #include "CharCodeToUnicode.h"
21 #include "WebFont.h"
22
WebFont(GfxFont * gfxFontA,XRef * xref)23 WebFont::WebFont(GfxFont *gfxFontA, XRef *xref) {
24 GfxFontType type;
25 Ref id;
26
27 gfxFont = gfxFontA;
28 fontBuf = NULL;
29 ffTrueType = NULL;
30 ffType1C = NULL;
31 isOpenType = gFalse;
32
33 if (gfxFont->getEmbeddedFontID(&id)) {
34 type = gfxFont->getType();
35 if (type == fontTrueType ||
36 type == fontTrueTypeOT ||
37 type == fontCIDType2 ||
38 type == fontCIDType2OT) {
39 if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
40 ffTrueType = FoFiTrueType::make(fontBuf, fontLength, 0);
41 }
42 } else if (type == fontType1C ||
43 type == fontCIDType0C) {
44 if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
45 ffType1C = FoFiType1C::make(fontBuf, fontLength);
46 }
47 } else if (type == fontType1COT ||
48 type == fontCIDType0COT) {
49 if ((fontBuf = gfxFont->readEmbFontFile(xref, &fontLength))) {
50 isOpenType = gTrue;
51 }
52 }
53 }
54 }
55
~WebFont()56 WebFont::~WebFont() {
57 delete ffTrueType;
58 delete ffType1C;
59 gfree(fontBuf);
60 }
61
canWriteTTF()62 GBool WebFont::canWriteTTF() {
63 return ffTrueType != NULL;
64 }
65
canWriteOTF()66 GBool WebFont::canWriteOTF() {
67 return ffType1C || isOpenType;
68 }
69
writeToFile(void * stream,const char * data,int len)70 static void writeToFile(void *stream, const char *data, int len) {
71 fwrite(data, 1, len, (FILE *)stream);
72 }
73
writeTTF(const char * fontFilePath)74 GBool WebFont::writeTTF(const char *fontFilePath) {
75 FILE *out;
76 int *codeToGID;
77 Guchar *cmapTable;
78 GBool freeCodeToGID;
79 int nCodes, cmapTableLength;
80
81 if (!ffTrueType) {
82 return gFalse;
83 }
84 if (gfxFont->isCIDFont()) {
85 codeToGID = ((GfxCIDFont *)gfxFont)->getCIDToGID();
86 nCodes = ((GfxCIDFont *)gfxFont)->getCIDToGIDLen();
87 if (!codeToGID) {
88 nCodes = ffTrueType->getNumGlyphs();
89 }
90 freeCodeToGID = gFalse;
91 } else {
92 codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ffTrueType);
93 nCodes = 256;
94 freeCodeToGID = gTrue;
95 }
96 cmapTable = makeUnicodeCmapTable(codeToGID, nCodes, &cmapTableLength);
97 if (freeCodeToGID) {
98 gfree(codeToGID);
99 }
100 if (!cmapTable) {
101 return gFalse;
102 }
103 if (!(out = fopen(fontFilePath, "wb"))) {
104 gfree(cmapTable);
105 return gFalse;
106 }
107 ffTrueType->writeTTF(writeToFile, out, NULL, NULL,
108 cmapTable, cmapTableLength);
109 fclose(out);
110 gfree(cmapTable);
111 return gTrue;
112 }
113
writeOTF(const char * fontFilePath)114 GBool WebFont::writeOTF(const char *fontFilePath) {
115 int *codeToGID;
116 Gushort *widths;
117 Guchar *cmapTable;
118 FILE *out;
119 int nCodes, nWidths, cmapTableLength;
120
121 if (ffType1C) {
122 if (gfxFont->getType() == fontType1C) {
123 codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ffType1C);
124 if (!(cmapTable = makeUnicodeCmapTable(codeToGID, 256,
125 &cmapTableLength))) {
126 gfree(codeToGID);
127 return gFalse;
128 }
129 widths = makeType1CWidths(codeToGID, 256, &nWidths);
130 gfree(codeToGID);
131 } else { // fontCIDType0C
132 codeToGID = ffType1C->getCIDToGIDMap(&nCodes);
133 if (!(cmapTable = makeUnicodeCmapTable(codeToGID, nCodes,
134 &cmapTableLength))) {
135 gfree(codeToGID);
136 return gFalse;
137 }
138 widths = makeCIDType0CWidths(codeToGID, nCodes, &nWidths);
139 gfree(codeToGID);
140 }
141 if (!(out = fopen(fontFilePath, "wb"))) {
142 gfree(cmapTable);
143 gfree(widths);
144 return gFalse;
145 }
146 ffType1C->convertToOpenType(writeToFile, out,
147 nWidths, widths,
148 cmapTable, cmapTableLength);
149 fclose(out);
150 gfree(cmapTable);
151 gfree(widths);
152
153 } else if (isOpenType) {
154 if (!(out = fopen(fontFilePath, "wb"))) {
155 return gFalse;
156 }
157 if (fwrite(fontBuf, 1, fontLength, out) != (Guint)fontLength) {
158 fclose(out);
159 return gFalse;
160 }
161 fclose(out);
162
163 } else {
164 return gFalse;
165 }
166
167 return gTrue;
168 }
169
makeType1CWidths(int * codeToGID,int nCodes,int * nWidths)170 Gushort *WebFont::makeType1CWidths(int *codeToGID, int nCodes,
171 int *nWidths) {
172 Gushort *widths;
173 Gushort width;
174 int widthsLen, gid, i;
175
176 widthsLen = ffType1C->getNumGlyphs();
177 widths = (Gushort *)gmallocn(widthsLen, sizeof(Gushort));
178 for (i = 0; i < widthsLen; ++i) {
179 widths[i] = 0;
180 }
181 for (i = 0; i < nCodes; ++i) {
182 gid = codeToGID[i];
183 if (gid < 0 || gid >= widthsLen) {
184 continue;
185 }
186 width = (Gushort)(((Gfx8BitFont *)gfxFont)->getWidth((Guchar)i)
187 * 1000 + 0.5);
188 if (width == 0) {
189 continue;
190 }
191 widths[gid] = width;
192 }
193 *nWidths = widthsLen;
194 return widths;
195 }
196
makeCIDType0CWidths(int * codeToGID,int nCodes,int * nWidths)197 Gushort *WebFont::makeCIDType0CWidths(int *codeToGID, int nCodes,
198 int *nWidths) {
199 Gushort *widths;
200 Gushort width;
201 int widthsLen, gid, i;
202
203 widthsLen = ffType1C->getNumGlyphs();
204 widths = (Gushort *)gmallocn(widthsLen, sizeof(Gushort));
205 for (i = 0 ; i < widthsLen; ++i) {
206 widths[i] = 0;
207 }
208 for (i = 0; i < nCodes; ++i) {
209 gid = codeToGID[i];
210 if (gid < 0 || gid >= widthsLen) {
211 continue;
212 }
213 width = (Gushort)(((GfxCIDFont *)gfxFont)->getWidth((CID)i)
214 * 1000 + 0.5);
215 if (width == 0) {
216 continue;
217 }
218 widths[gid] = width;
219 }
220 *nWidths = widthsLen;
221 return widths;
222 }
223
makeUnicodeCmapTable(int * codeToGID,int nCodes,int * unicodeCmapLength)224 Guchar *WebFont::makeUnicodeCmapTable(int *codeToGID, int nCodes,
225 int *unicodeCmapLength) {
226 int *unicodeToGID;
227 Guchar *cmapTable;
228 int unicodeToGIDLength, nMappings, len;
229 int nSegs, searchRange, entrySelector, rangeShift;
230 int glyphIdOffset, idRangeOffset;
231 int start, end, c, i;
232
233 if (!(unicodeToGID = makeUnicodeToGID(codeToGID, nCodes,
234 &unicodeToGIDLength))) {
235 return NULL;
236 }
237
238 // count the valid code-to-glyph mappings, and the sequences of
239 // consecutive valid mappings
240 // (note: char code 65535 is used to mark the end of table)
241 nMappings = 0;
242 nSegs = 1; // count the last segment, mapping 65535
243 for (c = 0; c < unicodeToGIDLength && c <= 65534; ++c) {
244 if (unicodeToGID[c]) {
245 ++nMappings;
246 if (c == 0 || !unicodeToGID[c-1]) {
247 ++nSegs;
248 }
249 }
250 }
251
252 i = 1;
253 entrySelector = 0;
254 while (2 * i <= nSegs) {
255 i *= 2;
256 ++entrySelector;
257 }
258 searchRange = 1 << (entrySelector + 1);
259 rangeShift = 2 * nSegs - searchRange;
260
261 len = 28 + nSegs * 8 + nMappings * 2;
262 cmapTable = (Guchar *)gmalloc(len);
263
264 // header
265 cmapTable[ 0] = 0x00; // table version
266 cmapTable[ 1] = 0x00;
267 cmapTable[ 2] = 0x00; // number of cmaps
268 cmapTable[ 3] = 0x01;
269 cmapTable[ 4] = 0x00; // platform[0]
270 cmapTable[ 5] = 0x03;
271 cmapTable[ 6] = 0x00; // encoding[0]
272 cmapTable[ 7] = 0x01;
273 cmapTable[ 8] = 0x00; // offset[0]
274 cmapTable[ 9] = 0x00;
275 cmapTable[10] = 0x00;
276 cmapTable[11] = 0x0c;
277
278 // table info
279 cmapTable[12] = 0x00; // cmap format
280 cmapTable[13] = 0x04;
281 cmapTable[14] = (Guchar)((len - 12) >> 8); // cmap length
282 cmapTable[15] = (Guchar)(len - 12);
283 cmapTable[16] = 0x00; // cmap version
284 cmapTable[17] = 0x00;
285 cmapTable[18] = (Guchar)(nSegs >> 7); // segCountX2
286 cmapTable[19] = (Guchar)(nSegs << 1);
287 cmapTable[20] = (Guchar)(searchRange >> 8); // searchRange
288 cmapTable[21] = (Guchar)searchRange;
289 cmapTable[22] = (Guchar)(entrySelector >> 8); // entrySelector
290 cmapTable[23] = (Guchar)entrySelector;
291 cmapTable[24] = (Guchar)(rangeShift >> 8); // rangeShift
292 cmapTable[25] = (Guchar)rangeShift;
293 cmapTable[26 + nSegs*2 ] = 0; // reservedPad
294 cmapTable[26 + nSegs*2 + 1] = 0;
295
296 i = 0;
297 glyphIdOffset = 28 + nSegs*8;
298 for (c = 0; c < unicodeToGIDLength && c <= 65534; ++c) {
299 if (unicodeToGID[c]) {
300 if (c == 0 || !unicodeToGID[c-1]) {
301 start = c;
302 cmapTable[28 + nSegs*2 + i*2 ] = (Guchar)(start >> 8);
303 cmapTable[28 + nSegs*2 + i*2 + 1] = (Guchar)start;
304 cmapTable[28 + nSegs*4 + i*2 ] = (Guchar)0; // idDelta
305 cmapTable[28 + nSegs*4 + i*2 + 1] = (Guchar)0;
306 idRangeOffset = glyphIdOffset - (28 + nSegs*6 + i*2);
307 cmapTable[28 + nSegs*6 + i*2 ] = (Guchar)(idRangeOffset >> 8);
308 cmapTable[28 + nSegs*6 + i*2 + 1] = (Guchar)idRangeOffset;
309 }
310 if (c == 65534 || !unicodeToGID[c+1]) {
311 end = c;
312 cmapTable[26 + i*2 ] = (Guchar)(end >> 8);
313 cmapTable[26 + i*2 + 1] = (Guchar)end;
314 ++i;
315 }
316 cmapTable[glyphIdOffset++] = (Guchar)(unicodeToGID[c] >> 8);
317 cmapTable[glyphIdOffset++] = (Guchar)unicodeToGID[c];
318 }
319 }
320
321 // last segment maps code 65535 to GID 0
322 cmapTable[26 + i*2 ] = (Guchar)0xff; // end
323 cmapTable[26 + i*2 + 1] = (Guchar)0xff;
324 cmapTable[28 + nSegs*2 + i*2 ] = (Guchar)0xff; // start
325 cmapTable[28 + nSegs*2 + i*2 + 1] = (Guchar)0xff;
326 cmapTable[28 + nSegs*4 + i*2 ] = (Guchar)0; // idDelta
327 cmapTable[28 + nSegs*4 + i*2 + 1] = (Guchar)1;
328 cmapTable[28 + nSegs*6 + i*2 ] = (Guchar)0; // idRangeOffset
329 cmapTable[28 + nSegs*6 + i*2 + 1] = (Guchar)0;
330
331 gfree(unicodeToGID);
332
333 *unicodeCmapLength = len;
334 return cmapTable;
335 }
336
makeUnicodeToGID(int * codeToGID,int nCodes,int * unicodeToGIDLength)337 int *WebFont::makeUnicodeToGID(int *codeToGID, int nCodes,
338 int *unicodeToGIDLength) {
339 int *unicodeToGID;
340 CharCodeToUnicode *ctu;
341 Unicode u[2];
342 int len, size, newSize, uLen, c, gid;
343
344 if (gfxFont->isCIDFont()) {
345 if (!(ctu = ((GfxCIDFont *)gfxFont)->getToUnicode())) {
346 return NULL;
347 }
348 } else {
349 ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode();
350 }
351
352 len = 0;
353 size = 256;
354 unicodeToGID = (int *)gmallocn(size, sizeof(int));
355 memset(unicodeToGID, 0, size * sizeof(int));
356 for (c = 0; c < nCodes; ++c) {
357 gid = codeToGID ? codeToGID[c] : c;
358 if (gid < 0 || gid >= 65536) {
359 continue;
360 }
361 uLen = ctu->mapToUnicode(c, u, 2);
362 if (uLen != 1) {
363 continue;
364 }
365 if (u[0] >= 65536) { // sanity check
366 continue;
367 }
368 if ((int)u[0] >= size) {
369 newSize = 2 * size;
370 while ((int)u[0] >= newSize) {
371 newSize *= 2;
372 }
373 unicodeToGID = (int *)greallocn(unicodeToGID, newSize, sizeof(int));
374 memset(unicodeToGID + size, 0, (newSize - size) * sizeof(int));
375 size = newSize;
376 }
377 unicodeToGID[u[0]] = gid;
378 if ((int)u[0] >= len) {
379 len = u[0] + 1;
380 }
381 }
382
383 ctu->decRefCnt();
384
385 *unicodeToGIDLength = len;
386 return unicodeToGID;
387 }
388