3 This is dvipdfmx, an eXtended version of dvipdfm by Mark A. Wicks.
5 Copyright (C) 2002-2012 by Jin-Hwan Cho and Shunsaku Hirata,
6 the dvipdfmx project team.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 * Subsetting glyf, updating loca, hmtx, ...
39 #define NUM_GLYPH_LIMIT 65534
40 #define TABLE_DATA_ALLOC_SIZE 40960
41 #define GLYPH_ARRAY_ALLOC_SIZE 256
44 find_empty_slot (struct tt_glyphs *g)
50 for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
51 if (!(g->used_slot[gid/8] & (1 << (7 - (gid % 8)))))
54 if (gid == NUM_GLYPH_LIMIT)
55 ERROR("No empty glyph slot available.");
61 tt_find_glyph (struct tt_glyphs *g, USHORT gid)
63 USHORT idx, new_gid = 0;
67 for (idx = 0; idx < g->num_glyphs; idx++) {
68 if (gid == g->gd[idx].ogid) {
69 new_gid = g->gd[idx].gid;
78 tt_get_index (struct tt_glyphs *g, USHORT gid)
84 for (idx = 0; idx < g->num_glyphs; idx++) {
85 if (gid == g->gd[idx].gid)
88 if (idx == g->num_glyphs)
95 tt_add_glyph (struct tt_glyphs *g, USHORT gid, USHORT new_gid)
99 if (g->used_slot[new_gid/8] & (1 << (7 - (new_gid % 8)))) {
100 WARN("Slot %u already used.", new_gid);
102 if (g->num_glyphs+1 >= NUM_GLYPH_LIMIT)
103 ERROR("Too many glyphs.");
105 if (g->num_glyphs >= g->max_glyphs) {
106 g->max_glyphs += GLYPH_ARRAY_ALLOC_SIZE;
107 g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
109 g->gd[g->num_glyphs].gid = new_gid;
110 g->gd[g->num_glyphs].ogid = gid;
111 g->gd[g->num_glyphs].length = 0;
112 g->gd[g->num_glyphs].data = NULL;
113 g->used_slot[new_gid/8] |= (1 << (7 - (new_gid % 8)));
117 if (new_gid > g->last_gid) {
118 g->last_gid = new_gid;
132 g = NEW(1, struct tt_glyphs);
141 g->used_slot = NEW(8192, unsigned char);
142 memset(g->used_slot, 0, 8192);
143 tt_add_glyph(g, 0, 0);
149 tt_build_finish (struct tt_glyphs *g)
154 for (idx = 0; idx < g->num_glyphs; idx++) {
156 RELEASE(g->gd[idx].data);
161 RELEASE(g->used_slot);
167 glyf_cmp (const void *v1, const void *v2)
170 const struct tt_glyph_desc *sv1, *sv2;
172 sv1 = (const struct tt_glyph_desc *) v1;
173 sv2 = (const struct tt_glyph_desc *) v2;
175 if (sv1->gid == sv2->gid)
177 else if (sv1->gid < sv2->gid)
186 * TrueType outline data.
188 #define ARG_1_AND_2_ARE_WORDS (1 << 0)
189 #define ARGS_ARE_XY_VALUES (1 << 1)
190 #define ROUND_XY_TO_GRID (1 << 2)
191 #define WE_HAVE_A_SCALE (1 << 3)
192 #define RESERVED (1 << 4)
193 #define MORE_COMPONENT (1 << 5)
194 #define WE_HAVE_AN_X_AND_Y_SCALE (1 << 6)
195 #define WE_HAVE_A_TWO_BY_TWO (1 << 7)
196 #define WE_HAVE_INSTRUCTIONS (1 << 8)
197 #define USE_MY_METRICS (1 << 9)
200 tt_build_tables (sfnt *sfont, struct tt_glyphs *g)
202 char *hmtx_table_data = NULL, *loca_table_data = NULL;
203 char *glyf_table_data = NULL;
204 ULONG hmtx_table_size, loca_table_size, glyf_table_size;
205 /* some information available from other TrueType table */
206 struct tt_head_table *head = NULL;
207 struct tt_hhea_table *hhea = NULL;
208 struct tt_maxp_table *maxp = NULL;
209 struct tt_longMetrics *hmtx, *vmtx = NULL;
210 struct tt_os2__table *os2;
212 ULONG *location, offset;
214 USHORT *w_stat; /* Estimate most frequently appeared width */
220 sfont->ft_face == NULL
222 sfont->stream == NULL
225 ERROR("File not opened.");
227 if (sfont->type != SFNT_TYPE_TRUETYPE &&
228 sfont->type != SFNT_TYPE_TTC &&
229 sfont->type != SFNT_TYPE_DFONT)
230 ERROR("Invalid font type");
232 if (g->num_glyphs > NUM_GLYPH_LIMIT)
233 ERROR("Too many glyphs.");
236 * Read head, hhea, maxp, loca:
238 * unitsPerEm --> head
239 * numHMetrics --> hhea
240 * indexToLocFormat --> head
243 head = tt_read_head_table(sfont);
244 hhea = tt_read_hhea_table(sfont);
245 maxp = tt_read_maxp_table(sfont);
247 if (hhea->metricDataFormat != 0)
248 ERROR("Unknown metricDataFormat.");
250 g->emsize = head->unitsPerEm;
252 sfnt_locate_table(sfont, "hmtx");
253 hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numOfLongHorMetrics, hhea->numOfExSideBearings);
255 os2 = tt_read_os2__table(sfont);
256 g->default_advh = os2->sTypoAscender - os2->sTypoDescender;
257 g->default_tsb = g->default_advh - os2->sTypoAscender;
259 if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
260 struct tt_vhea_table *vhea;
261 vhea = tt_read_vhea_table(sfont);
262 sfnt_locate_table(sfont, "vmtx");
263 vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics, vhea->numOfExSideBearings);
269 sfnt_locate_table(sfont, "loca");
270 location = NEW(maxp->numGlyphs + 1, ULONG);
271 if (head->indexToLocFormat == 0) {
272 for (i = 0; i <= maxp->numGlyphs; i++)
273 location[i] = 2*((ULONG) sfnt_get_ushort(sfont));
274 } else if (head->indexToLocFormat == 1) {
275 for (i = 0; i <= maxp->numGlyphs; i++)
276 location[i] = sfnt_get_ulong(sfont);
278 ERROR("Unknown IndexToLocFormat.");
281 w_stat = NEW(g->emsize+2, USHORT);
282 memset(w_stat, 0, sizeof(USHORT)*(g->emsize+2));
286 offset = sfnt_locate_table(sfont, "glyf");
288 * The num_glyphs may grow when composite glyph is found.
289 * A component of glyph refered by a composite glyph is appended
290 * to used_glyphs if it is not already registered in used_glyphs.
291 * Glyph programs of composite glyphs are modified so that it
292 * correctly refer to new gid of their components.
294 for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
295 USHORT gid; /* old gid */
298 SHORT number_of_contours;
300 if (i >= g->num_glyphs) /* finished */
304 if (gid >= maxp->numGlyphs)
305 ERROR("Invalid glyph index (gid %u)", gid);
308 len = location[gid+1] - loc;
309 g->gd[i].advw = hmtx[gid].advance;
310 g->gd[i].lsb = hmtx[gid].sideBearing;
312 g->gd[i].advh = vmtx[gid].advance;
313 g->gd[i].tsb = vmtx[gid].sideBearing;
315 g->gd[i].advh = g->default_advh;
316 g->gd[i].tsb = g->default_tsb;
318 g->gd[i].length = len;
319 g->gd[i].data = NULL;
320 if (g->gd[i].advw <= g->emsize) {
321 w_stat[g->gd[i].advw] += 1;
323 w_stat[g->emsize+1] += 1; /* larger than em */
326 if (len == 0) { /* Does not contains any data. */
328 } else if (len < 10) {
329 ERROR("Invalid TrueType glyph data (gid %u).", gid);
332 g->gd[i].data = p = NEW(len, BYTE);
335 sfnt_seek_set(sfont, offset+loc);
336 number_of_contours = sfnt_get_short(sfont);
337 p += sfnt_put_short(p, number_of_contours);
339 /* BoundingBox: FWord x 4 */
340 g->gd[i].llx = sfnt_get_short(sfont);
341 g->gd[i].lly = sfnt_get_short(sfont);
342 g->gd[i].urx = sfnt_get_short(sfont);
343 g->gd[i].ury = sfnt_get_short(sfont);
346 if (!vmtx) /* vertOriginY == sTypeAscender */
347 g->gd[i].tsb = g->default_advh - g->default_tsb - g->gd[i].ury;
349 p += sfnt_put_short(p, g->gd[i].llx);
350 p += sfnt_put_short(p, g->gd[i].lly);
351 p += sfnt_put_short(p, g->gd[i].urx);
352 p += sfnt_put_short(p, g->gd[i].ury);
354 /* Read evrything else. */
355 sfnt_read(p, len - 10, sfont);
357 * Fix GIDs of composite glyphs.
359 if (number_of_contours < 0) {
360 USHORT flags, cgid, new_gid; /* flag, gid of a component */
363 ERROR("Invalid TrueType glyph data (gid %u): %u bytes", gid, len);
365 * Flags and gid of component glyph are both USHORT.
367 flags = ((*p) << 8)| *(p+1);
369 cgid = ((*p) << 8)| *(p+1);
370 if (cgid >= maxp->numGlyphs) {
371 ERROR("Invalid gid (%u > %u) in composite glyph %u.", cgid, maxp->numGlyphs, gid);
373 new_gid = tt_find_glyph(g, cgid);
375 new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
377 p += sfnt_put_ushort(p, new_gid);
379 * Just skip remaining part.
381 p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
382 if (flags & WE_HAVE_A_SCALE) /* F2Dot14 */
384 else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 2 */
386 else if (flags & WE_HAVE_A_TWO_BY_TWO) /* F2Dot14 x 4 */
388 } while (flags & MORE_COMPONENT);
390 * TrueType instructions comes here:
391 * length_of_instruction (ushort)
392 * instruction (byte * length_of_instruction)
404 g->dw = g->gd[0].advw;
405 for (i = 0; i < g->emsize + 1; i++) {
406 if (w_stat[i] > max_count) {
407 max_count = w_stat[i];
414 qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
416 USHORT prev, last_advw;
418 int padlen, num_hm_known;
420 glyf_table_size = 0UL;
422 last_advw = g->gd[g->num_glyphs - 1].advw;
423 for (i = g->num_glyphs - 1; i >= 0; i--) {
424 padlen = (g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0;
425 glyf_table_size += g->gd[i].length + padlen;
426 if (!num_hm_known && last_advw != g->gd[i].advw) {
427 hhea->numOfLongHorMetrics = g->gd[i].gid + 2;
431 /* All advance widths are same. */
433 hhea->numOfLongHorMetrics = 1;
435 hmtx_table_size = hhea->numOfLongHorMetrics * 2 + (g->last_gid + 1) * 2;
438 * Choosing short format does not always give good result
439 * when compressed. Sometimes increases size.
441 if (glyf_table_size < 0x20000UL) {
442 head->indexToLocFormat = 0;
443 loca_table_size = (g->last_gid + 2)*2;
445 head->indexToLocFormat = 1;
446 loca_table_size = (g->last_gid + 2)*4;
449 hmtx_table_data = p = NEW(hmtx_table_size, char);
450 loca_table_data = q = NEW(loca_table_size, char);
451 glyf_table_data = NEW(glyf_table_size, char);
453 offset = 0UL; prev = 0;
454 for (i = 0; i < g->num_glyphs; i++) {
456 gap = (long) g->gd[i].gid - prev - 1;
457 for (j = 1; j <= gap; j++) {
458 if (prev + j == hhea->numOfLongHorMetrics - 1) {
459 p += sfnt_put_ushort(p, last_advw);
460 } else if (prev + j < hhea->numOfLongHorMetrics) {
461 p += sfnt_put_ushort(p, 0);
463 p += sfnt_put_short (p, 0);
464 if (head->indexToLocFormat == 0) {
465 q += sfnt_put_ushort(q, (USHORT) (offset/2));
467 q += sfnt_put_ulong(q, offset);
470 padlen = (g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0;
471 if (g->gd[i].gid < hhea->numOfLongHorMetrics) {
472 p += sfnt_put_ushort(p, g->gd[i].advw);
474 p += sfnt_put_short (p, g->gd[i].lsb);
475 if (head->indexToLocFormat == 0) {
476 q += sfnt_put_ushort(q, (USHORT) (offset/2));
478 q += sfnt_put_ulong(q, offset);
480 memset(glyf_table_data + offset, 0, g->gd[i].length + padlen);
481 memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
482 offset += g->gd[i].length + padlen;
484 /* free data here since it consume much memory */
485 RELEASE(g->gd[i].data);
486 g->gd[i].length = 0; g->gd[i].data = NULL;
488 if (head->indexToLocFormat == 0) {
489 q += sfnt_put_ushort(q, (USHORT) (offset/2));
491 q += sfnt_put_ulong(q, offset);
494 sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data, hmtx_table_size);
495 sfnt_set_table(sfont, "loca", (char *) loca_table_data, loca_table_size);
496 sfnt_set_table(sfont, "glyf", (char *) glyf_table_data, glyf_table_size);
499 head->checkSumAdjustment = 0;
500 maxp->numGlyphs = g->last_gid + 1;
503 sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
504 sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
505 sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
515 tt_get_metrics (sfnt *sfont, struct tt_glyphs *g)
517 struct tt_head_table *head = NULL;
518 struct tt_hhea_table *hhea = NULL;
519 struct tt_maxp_table *maxp = NULL;
520 struct tt_longMetrics *hmtx, *vmtx = NULL;
521 struct tt_os2__table *os2;
523 ULONG *location, offset;
531 sfont->ft_face == NULL
533 sfont->stream == NULL
536 ERROR("File not opened.");
538 if (sfont->type != SFNT_TYPE_TRUETYPE &&
539 sfont->type != SFNT_TYPE_TTC &&
540 sfont->type != SFNT_TYPE_DFONT)
541 ERROR("Invalid font type");
544 * Read head, hhea, maxp, loca:
546 * unitsPerEm --> head
547 * numHMetrics --> hhea
548 * indexToLocFormat --> head
551 head = tt_read_head_table(sfont);
552 hhea = tt_read_hhea_table(sfont);
553 maxp = tt_read_maxp_table(sfont);
555 if (hhea->metricDataFormat != 0)
556 ERROR("Unknown metricDataFormat.");
558 g->emsize = head->unitsPerEm;
560 sfnt_locate_table(sfont, "hmtx");
561 hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numOfLongHorMetrics, hhea->numOfExSideBearings);
563 os2 = tt_read_os2__table(sfont);
564 g->default_advh = os2->sTypoAscender - os2->sTypoDescender;
565 g->default_tsb = g->default_advh - os2->sTypoAscender;
567 if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
568 struct tt_vhea_table *vhea;
569 vhea = tt_read_vhea_table(sfont);
570 sfnt_locate_table(sfont, "vmtx");
571 vmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, vhea->numOfLongVerMetrics, vhea->numOfExSideBearings);
577 sfnt_locate_table(sfont, "loca");
578 location = NEW(maxp->numGlyphs + 1, ULONG);
579 if (head->indexToLocFormat == 0) {
580 for (i = 0; i <= maxp->numGlyphs; i++)
581 location[i] = 2*((ULONG) sfnt_get_ushort(sfont));
582 } else if (head->indexToLocFormat == 1) {
583 for (i = 0; i <= maxp->numGlyphs; i++)
584 location[i] = sfnt_get_ulong(sfont);
586 ERROR("Unknown IndexToLocFormat.");
589 w_stat = NEW(g->emsize+2, USHORT);
590 memset(w_stat, 0, sizeof(USHORT)*(g->emsize+2));
594 offset = sfnt_locate_table(sfont, "glyf");
595 for (i = 0; i < g->num_glyphs; i++) {
596 USHORT gid; /* old gid */
600 if (gid >= maxp->numGlyphs)
601 ERROR("Invalid glyph index (gid %u)", gid);
604 len = location[gid+1] - loc;
605 g->gd[i].advw = hmtx[gid].advance;
606 g->gd[i].lsb = hmtx[gid].sideBearing;
608 g->gd[i].advh = vmtx[gid].advance;
609 g->gd[i].tsb = vmtx[gid].sideBearing;
611 g->gd[i].advh = g->default_advh;
612 g->gd[i].tsb = g->default_tsb;
614 g->gd[i].length = len;
615 g->gd[i].data = NULL;
617 if (g->gd[i].advw <= g->emsize) {
618 w_stat[g->gd[i].advw] += 1;
620 w_stat[g->emsize+1] += 1; /* larger than em */
623 if (len == 0) { /* Does not contains any data. */
625 } else if (len < 10) {
626 ERROR("Invalid TrueType glyph data (gid %u).", gid);
629 sfnt_seek_set(sfont, offset+loc);
630 (void) sfnt_get_short(sfont);
632 /* BoundingBox: FWord x 4 */
633 g->gd[i].llx = sfnt_get_short(sfont);
634 g->gd[i].lly = sfnt_get_short(sfont);
635 g->gd[i].urx = sfnt_get_short(sfont);
636 g->gd[i].ury = sfnt_get_short(sfont);
639 if (!vmtx) /* vertOriginY == sTypeAscender */
640 g->gd[i].tsb = g->default_advh - g->default_tsb - g->gd[i].ury;
656 g->dw = g->gd[0].advw;
657 for (i = 0; i < g->emsize + 1; i++) {
658 if (w_stat[i] > max_count) {
659 max_count = w_stat[i];