1 /* This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
2 
3     Copyright (C) 2002-2014 by Jin-Hwan Cho and Shunsaku Hirata,
4     the dvipdfmx project team.
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
19 */
20 
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24 
25 #include <stdio.h>
26 
27 #include "system.h"
28 #include "error.h"
29 #include "mem.h"
30 #include "mfileio.h"
31 
32 #include "sfnt.h"
33 #include "tt_table.h"
34 
35 /*
36   tables contains information refered by other tables
37   maxp->numGlyphs, etc --> loca, etc
38   hhea->numOfLongHorMetrics --> hmtx
39   head->indexToLocFormat --> loca
40   head->glyphDataFormat --> glyf
41 */
42 
tt_pack_head_table(struct tt_head_table * table)43 char *tt_pack_head_table (struct tt_head_table *table)
44 {
45   int i;
46   char *p, *data;
47 
48   if (table == NULL)
49     ERROR("passed NULL pointer\n");
50 
51   p = data = NEW(TT_HEAD_TABLE_SIZE, char);
52   p += sfnt_put_ulong(p, table->version);
53   p += sfnt_put_ulong(p, table->fontRevision);
54   p += sfnt_put_ulong(p, table->checkSumAdjustment);
55   p += sfnt_put_ulong(p, table->magicNumber);
56   p += sfnt_put_ushort(p, table->flags);
57   p += sfnt_put_ushort(p, table->unitsPerEm);
58   for (i=0; i<8; i++) {
59     *(p++) = (table->created)[i];
60   }
61   for (i=0; i<8; i++) {
62     *(p++) = (table->modified)[i];
63   }
64   p += sfnt_put_short(p, table->xMin);
65   p += sfnt_put_short(p, table->yMin);
66   p += sfnt_put_short(p, table->xMax);
67   p += sfnt_put_short(p, table->yMax);
68   p += sfnt_put_ushort(p, table->macStyle);
69   p += sfnt_put_ushort(p, table->lowestRecPPEM);
70   p += sfnt_put_short(p, table->fontDirectionHint);
71   p += sfnt_put_short(p, table->indexToLocFormat);
72   p += sfnt_put_short(p, table->glyphDataFormat);
73 
74   return data;
75 }
76 
tt_read_head_table(sfnt * sfont)77 struct tt_head_table *tt_read_head_table (sfnt *sfont)
78 {
79   int i;
80   struct tt_head_table *table = NEW(1, struct tt_head_table);
81 
82   sfnt_locate_table(sfont, "head");
83 
84   table->version = sfnt_get_ulong(sfont);
85   table->fontRevision = sfnt_get_ulong(sfont);
86   table->checkSumAdjustment = sfnt_get_ulong(sfont);
87   table->magicNumber = sfnt_get_ulong(sfont);
88   table->flags = sfnt_get_ushort(sfont);
89   table->unitsPerEm = sfnt_get_ushort(sfont);
90   for (i=0; i<8; i++) {
91     (table->created)[i] = sfnt_get_byte (sfont);
92   }
93   for (i=0; i<8; i++) {
94     (table->modified)[i] = sfnt_get_byte (sfont);
95   }
96   table->xMin = sfnt_get_short(sfont);
97   table->yMin = sfnt_get_short(sfont);
98   table->xMax = sfnt_get_short(sfont);
99   table->yMax = sfnt_get_short(sfont);
100   table->macStyle = sfnt_get_short(sfont);
101   table->lowestRecPPEM = sfnt_get_short(sfont);
102   table->fontDirectionHint = sfnt_get_short(sfont);
103   table->indexToLocFormat = sfnt_get_short(sfont);
104   table->glyphDataFormat = sfnt_get_short(sfont);
105 
106   return table;
107 }
108 
tt_pack_maxp_table(struct tt_maxp_table * table)109 char *tt_pack_maxp_table (struct tt_maxp_table *table)
110 {
111   char *p, *data;
112 
113   p = data = NEW(TT_MAXP_TABLE_SIZE, char);
114   p += sfnt_put_ulong(p, table->version);
115   p += sfnt_put_ushort(p, table->numGlyphs);
116   p += sfnt_put_ushort(p, table->maxPoints);
117   p += sfnt_put_ushort(p, table->maxContours);
118   p += sfnt_put_ushort(p, table->maxComponentPoints);
119   p += sfnt_put_ushort(p, table->maxComponentContours);
120   p += sfnt_put_ushort(p, table->maxZones);
121   p += sfnt_put_ushort(p, table->maxTwilightPoints);
122   p += sfnt_put_ushort(p, table->maxStorage);
123   p += sfnt_put_ushort(p, table->maxFunctionDefs);
124   p += sfnt_put_ushort(p, table->maxInstructionDefs);
125   p += sfnt_put_ushort(p, table->maxStackElements);
126   p += sfnt_put_ushort(p, table->maxSizeOfInstructions);
127   p += sfnt_put_ushort(p, table->maxComponentElements);
128   p += sfnt_put_ushort(p, table->maxComponentDepth);
129 
130   return data;
131 }
132 
tt_read_maxp_table(sfnt * sfont)133 struct tt_maxp_table *tt_read_maxp_table (sfnt *sfont)
134 {
135   struct tt_maxp_table *table = NEW(1, struct tt_maxp_table);
136 
137   sfnt_locate_table(sfont, "maxp");
138 
139   table->version = sfnt_get_ulong(sfont);
140   table->numGlyphs = sfnt_get_ushort(sfont);
141   table->maxPoints = sfnt_get_ushort(sfont);
142   table->maxContours = sfnt_get_ushort(sfont);
143   table->maxComponentPoints = sfnt_get_ushort(sfont);
144   table->maxComponentContours = sfnt_get_ushort(sfont);
145   table->maxZones = sfnt_get_ushort(sfont);
146   table->maxTwilightPoints = sfnt_get_ushort(sfont);
147   table->maxStorage = sfnt_get_ushort(sfont);
148   table->maxFunctionDefs = sfnt_get_ushort(sfont);
149   table->maxInstructionDefs = sfnt_get_ushort(sfont);
150   table->maxStackElements = sfnt_get_ushort(sfont);
151   table->maxSizeOfInstructions = sfnt_get_ushort(sfont);
152   table->maxComponentElements = sfnt_get_ushort(sfont);
153   table->maxComponentDepth = sfnt_get_ushort(sfont);
154 
155   return table;
156 }
157 
tt_pack_hhea_table(struct tt_hhea_table * table)158 char *tt_pack_hhea_table (struct tt_hhea_table *table)
159 {
160   int   i;
161   char *p, *data;
162 
163   p  = data = NEW(TT_HHEA_TABLE_SIZE, char);
164   p += sfnt_put_ulong(p, table->version);
165   p += sfnt_put_short(p, table->ascent);
166   p += sfnt_put_short(p, table->descent);
167   p += sfnt_put_short(p, table->lineGap);
168   p += sfnt_put_ushort(p, table->advanceWidthMax);
169   p += sfnt_put_short(p, table->minLeftSideBearing);
170   p += sfnt_put_short(p, table->minRightSideBearing);
171   p += sfnt_put_short(p, table->xMaxExtent);
172   p += sfnt_put_short(p, table->caretSlopeRise);
173   p += sfnt_put_short(p, table->caretSlopeRun);
174   p += sfnt_put_short(p, table->caretOffset);
175   for (i = 0; i < 4; i++) {
176     p += sfnt_put_short(p, table->reserved[i]);
177   }
178   p += sfnt_put_short(p, table->metricDataFormat);
179   p += sfnt_put_ushort(p, table->numOfLongHorMetrics);
180 
181   return data;
182 }
183 
184 struct tt_hhea_table *
tt_read_hhea_table(sfnt * sfont)185 tt_read_hhea_table (sfnt *sfont)
186 {
187   int    i;
188   ULONG  len;
189   struct tt_hhea_table *table = NEW(1, struct tt_hhea_table);
190 
191   sfnt_locate_table(sfont, "hhea");
192 
193   table->version = sfnt_get_ulong(sfont);
194   table->ascent  = sfnt_get_short (sfont);
195   table->descent = sfnt_get_short(sfont);
196   table->lineGap = sfnt_get_short(sfont);
197   table->advanceWidthMax     = sfnt_get_ushort(sfont);
198   table->minLeftSideBearing  = sfnt_get_short(sfont);
199   table->minRightSideBearing = sfnt_get_short(sfont);
200   table->xMaxExtent     = sfnt_get_short(sfont);
201   table->caretSlopeRise = sfnt_get_short(sfont);
202   table->caretSlopeRun  = sfnt_get_short(sfont);
203   table->caretOffset    = sfnt_get_short(sfont);
204   for(i = 0; i < 4; i++) {
205     table->reserved[i] = sfnt_get_short(sfont);
206   }
207   table->metricDataFormat = sfnt_get_short(sfont);
208   if (table->metricDataFormat != 0)
209     ERROR("unknown metricDataFormat");
210   table->numOfLongHorMetrics = sfnt_get_ushort(sfont);
211 
212   len = sfnt_find_table_len(sfont, "hmtx");
213   table->numOfExSideBearings = (USHORT)((len - table->numOfLongHorMetrics * 4) / 2);
214 
215   return table;
216 }
217 
218 /* vhea */
219 #if 0
220 char *
221 tt_pack_vhea_table (struct tt_vhea_table *table)
222 {
223   int   i;
224   char *p, *data;
225 
226   p  = data = NEW(TT_VHEA_TABLE_SIZE, char);
227   p += sfnt_put_ulong(p, table->version);
228   p += sfnt_put_short(p, table->vertTypoAscender);
229   p += sfnt_put_short(p, table->vertTypoDescender);
230   p += sfnt_put_short(p, table->vertTypoLineGap);
231   p += sfnt_put_short(p, table->advanceHeightMax);  /* ushort ? */
232   p += sfnt_put_short(p, table->minTopSideBearing);
233   p += sfnt_put_short(p, table->minBottomSideBearing);
234   p += sfnt_put_short(p, table->yMaxExtent);
235   p += sfnt_put_short(p, table->caretSlopeRise);
236   p += sfnt_put_short(p, table->caretSlopeRun);
237   p += sfnt_put_short(p, table->caretOffset);
238   for(i = 0; i < 4; i++) {
239     p += sfnt_put_short(p, table->reserved[i]);
240   }
241   p += sfnt_put_short(p, table->metricDataFormat);
242   p += sfnt_put_ushort(p, table->numOfLongVerMetrics);
243 
244   return data;
245 }
246 #endif
247 
tt_read_vhea_table(sfnt * sfont)248 struct tt_vhea_table *tt_read_vhea_table (sfnt *sfont)
249 {
250   int   i;
251   ULONG len;
252   struct tt_vhea_table *table = NEW(1, struct tt_vhea_table);
253 
254   sfnt_locate_table(sfont, "vhea");
255 
256   table->version = sfnt_get_ulong(sfont);
257   table->vertTypoAscender = sfnt_get_short (sfont);
258   table->vertTypoDescender = sfnt_get_short(sfont);
259   table->vertTypoLineGap = sfnt_get_short(sfont);
260   table->advanceHeightMax = sfnt_get_short(sfont); /* ushort ? */
261   table->minTopSideBearing = sfnt_get_short(sfont);
262   table->minBottomSideBearing = sfnt_get_short(sfont);
263   table->yMaxExtent = sfnt_get_short(sfont);
264   table->caretSlopeRise = sfnt_get_short(sfont);
265   table->caretSlopeRun = sfnt_get_short(sfont);
266   table->caretOffset = sfnt_get_short(sfont);
267   for(i = 0; i < 4; i++) {
268     (table->reserved)[i] = sfnt_get_short(sfont);
269   }
270   table->metricDataFormat = sfnt_get_short(sfont);
271   table->numOfLongVerMetrics = sfnt_get_ushort(sfont);
272 
273   len = sfnt_find_table_len(sfont, "vmtx");
274   table->numOfExSideBearings = (USHORT)((len - table->numOfLongVerMetrics * 4) / 2);
275 
276   return table;
277 }
278 
279 
280 struct tt_VORG_table *
tt_read_VORG_table(sfnt * sfont)281 tt_read_VORG_table (sfnt *sfont)
282 {
283   struct tt_VORG_table *vorg;
284   ULONG  offset;
285   USHORT i;
286 
287   offset = sfnt_find_table_pos(sfont, "VORG");
288 
289   if (offset > 0) {
290     vorg = NEW(1, struct tt_VORG_table);
291 
292     sfnt_locate_table(sfont, "VORG");
293     if (sfnt_get_ushort(sfont) != 1 ||
294 	sfnt_get_ushort(sfont) != 0)
295       ERROR("Unsupported VORG version.");
296 
297     vorg->defaultVertOriginY    = sfnt_get_short(sfont);
298     vorg->numVertOriginYMetrics = sfnt_get_ushort(sfont);
299     vorg->vertOriginYMetrics    = NEW(vorg->numVertOriginYMetrics,
300 				      struct tt_vertOriginYMetrics);
301     /*
302      * The vertOriginYMetrics array must be sorted in increasing
303      * glyphIndex order.
304      */
305     for (i = 0;
306 	 i < vorg->numVertOriginYMetrics; i++) {
307       vorg->vertOriginYMetrics[i].glyphIndex  = sfnt_get_ushort(sfont);
308       vorg->vertOriginYMetrics[i].vertOriginY = sfnt_get_short(sfont);
309     }
310   } else {
311     vorg = NULL;
312   }
313 
314   return vorg;
315 }
316 
317 /*
318  * hmtx and vmtx
319  *
320  *  Reading/writing hmtx and vmtx depend on other tables, maxp and hhea/vhea.
321  */
322 
323 struct tt_longMetrics *
tt_read_longMetrics(sfnt * sfont,USHORT numGlyphs,USHORT numLongMetrics,USHORT numExSideBearings)324 tt_read_longMetrics (sfnt *sfont, USHORT numGlyphs, USHORT numLongMetrics, USHORT numExSideBearings)
325 {
326   struct tt_longMetrics *m;
327   USHORT gid, last_adv = 0;
328   SHORT  last_esb = 0;
329 
330   m = NEW(numGlyphs, struct tt_longMetrics);
331   for (gid = 0; gid < numGlyphs; gid++) {
332     if (gid < numLongMetrics)
333       last_adv = sfnt_get_ushort(sfont);
334     if (gid < numLongMetrics + numExSideBearings)
335       last_esb = sfnt_get_short(sfont);
336     m[gid].advance     = last_adv;
337     m[gid].sideBearing = last_esb;
338   }
339 
340   return m;
341 }
342 
343 /* OS/2 table */
344 /* this table may not exist */
345 struct tt_os2__table *
tt_read_os2__table(sfnt * sfont)346 tt_read_os2__table (sfnt *sfont)
347 {
348   struct tt_os2__table *table = NULL;
349   int    i;
350 
351   table = NEW(1, struct tt_os2__table);
352 
353   if (sfnt_find_table_pos(sfont, "OS/2") > 0) {
354     sfnt_locate_table(sfont, "OS/2");
355     table->version       = sfnt_get_ushort(sfont);
356     table->xAvgCharWidth = sfnt_get_short(sfont);
357     table->usWeightClass = sfnt_get_ushort(sfont);
358     table->usWidthClass  = sfnt_get_ushort(sfont);
359     table->fsType        = sfnt_get_short(sfont);
360     table->ySubscriptXSize   = sfnt_get_short(sfont);
361     table->ySubscriptYSize   = sfnt_get_short(sfont);
362     table->ySubscriptXOffset = sfnt_get_short(sfont);
363     table->ySubscriptYOffset = sfnt_get_short(sfont);
364     table->ySuperscriptXSize = sfnt_get_short(sfont);
365     table->ySuperscriptYSize = sfnt_get_short(sfont);
366     table->ySuperscriptXOffset = sfnt_get_short(sfont);
367     table->ySuperscriptYOffset = sfnt_get_short(sfont);
368     table->yStrikeoutSize      = sfnt_get_short(sfont);
369     table->yStrikeoutPosition  = sfnt_get_short(sfont);
370     table->sFamilyClass        = sfnt_get_short(sfont);
371     for (i = 0; i < 10; i++) {
372       table->panose[i] = sfnt_get_byte(sfont);
373     }
374     table->ulUnicodeRange1 = sfnt_get_ulong(sfont);
375     table->ulUnicodeRange2 = sfnt_get_ulong(sfont);
376     table->ulUnicodeRange3 = sfnt_get_ulong(sfont);
377     table->ulUnicodeRange4 = sfnt_get_ulong(sfont);
378     for (i = 0; i < 4; i++) {
379       table->achVendID[i] = sfnt_get_char(sfont);
380     }
381     table->fsSelection      = sfnt_get_ushort(sfont);
382     table->usFirstCharIndex = sfnt_get_ushort(sfont);
383     table->usLastCharIndex  = sfnt_get_ushort(sfont);
384     if (sfnt_find_table_len(sfont, "OS/2") >= 78) {
385       /* these fields are not present in the original Apple spec (68-byte table),
386          but Microsoft's version of "format 0" does include them... grr! */
387       table->sTypoAscender    = sfnt_get_short(sfont);
388       table->sTypoDescender   = sfnt_get_short(sfont);
389       table->sTypoLineGap     = sfnt_get_short(sfont);
390       table->usWinAscent      = sfnt_get_ushort(sfont);
391       table->usWinDescent     = sfnt_get_ushort(sfont);
392       if (table->version > 0) {
393         /* format 1 adds the following 2 fields */
394         table->ulCodePageRange1 = sfnt_get_ulong(sfont);
395         table->ulCodePageRange2 = sfnt_get_ulong(sfont);
396         if (table->version > 1) {
397           /* and formats 2 and 3 (current) include 5 more.... these share the
398              same fields, only the precise definition of some was changed */
399           table->sxHeight      = sfnt_get_short(sfont);
400           table->sCapHeight    = sfnt_get_short(sfont);
401           table->usDefaultChar = sfnt_get_ushort(sfont);
402           table->usBreakChar   = sfnt_get_ushort(sfont);
403           table->usMaxContext  = sfnt_get_ushort(sfont);
404         }
405       }
406     }
407   } else {
408 
409     /* used in add_CIDVMetrics() of cidtype0.c */
410     table->sTypoAscender  = 880;
411     table->sTypoDescender = -120;
412     /* used in tt_get_fontdesc() of tt_aux.c */
413     table->usWeightClass = 400U; /* Normal(Regular) */
414     table->xAvgCharWidth = 0; /* ignore */
415     table->version = 0; /* TrueType rev 1.5 */
416     table->fsType = 0; /* Installable Embedding */
417     table->fsSelection = 0U; /* All undefined */
418     table->sFamilyClass = 0; /* No Classification */
419     for (i = 0; i < 10; i++) {
420       table->panose[i] = 0; /* All Any */
421     }
422   }
423 
424   return table;
425 }
426 
427 USHORT
tt_get_name(sfnt * sfont,char * dest,USHORT destlen,USHORT plat_id,USHORT enco_id,USHORT lang_id,USHORT name_id)428 tt_get_name (sfnt *sfont, char *dest, USHORT destlen,
429 	     USHORT plat_id, USHORT enco_id,
430 	     USHORT lang_id, USHORT name_id)
431 {
432   USHORT length = 0;
433   USHORT num_names, string_offset;
434   ULONG  name_offset;
435   int    i;
436 
437   name_offset = sfnt_locate_table (sfont, "name");
438 
439   if (sfnt_get_ushort(sfont))
440     ERROR ("Expecting zero");
441 
442   num_names = sfnt_get_ushort(sfont);
443   string_offset = sfnt_get_ushort(sfont);
444   for (i=0;i<num_names;i++) {
445     USHORT p_id, e_id, n_id, l_id;
446     USHORT offset;
447 
448     p_id = sfnt_get_ushort(sfont);
449     e_id = sfnt_get_ushort(sfont);
450     l_id = sfnt_get_ushort(sfont);
451     n_id = sfnt_get_ushort(sfont);
452     length = sfnt_get_ushort(sfont);
453     offset = sfnt_get_ushort(sfont);
454     /* language ID value 0xffffu for `accept any language ID' */
455     if ((p_id == plat_id) && (e_id == enco_id) &&
456 	(lang_id == 0xffffu || l_id == lang_id) && (n_id == name_id)) {
457       if (length > destlen - 1) {
458 	WARN ("Name string too long (%u), truncating to %u", length, destlen);
459 	length = destlen - 1;
460       }
461       sfnt_seek_set (sfont, name_offset+string_offset+offset);
462       sfnt_read((unsigned char*)dest, length, sfont);
463       dest[length] = '\0';
464       break;
465     }
466   }
467   if (i == num_names) {
468     length = 0;
469   }
470 
471   return length;
472 }
473 
474 USHORT
tt_get_ps_fontname(sfnt * sfont,char * dest,USHORT destlen)475 tt_get_ps_fontname (sfnt *sfont, char *dest, USHORT destlen)
476 {
477   USHORT namelen = 0;
478 
479   /* First try Mac-Roman PS name and then Win-Unicode PS name */
480   if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 6)) != 0 ||
481       (namelen = tt_get_name(sfont, dest, destlen, 3, 1, 0x409u, 6)) != 0 ||
482       (namelen = tt_get_name(sfont, dest, destlen, 3, 5, 0x412u, 6)) != 0)
483     return namelen;
484 
485   WARN ("No valid PostScript name available");
486   /*
487     Workaround for some bad TTfonts:
488     Language ID value 0xffffu for `accept any language ID'
489   */
490   if ((namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0xffffu, 6)) == 0) {
491     /*
492       Finally falling back to Mac Roman name field.
493       Warning: Some bad Japanese TTfonts using SJIS encoded string in the
494       Mac Roman name field.
495     */
496     namelen = tt_get_name(sfont, dest, destlen, 1, 0, 0, 1);
497   }
498 
499   return namelen;
500 }
501