beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / font / tt_glyf.w
blob167d8df2038ac8bec44dd85e02ed22fb6e30169a
1 % tt_glyf.w
3 % Copyright 2002 by Jin-Hwan Cho and Shunsaku Hirata,
4 % the dvipdfmx project team <dvipdfmx@@project.ktug.or.kr>
5 % Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
7 % This file is part of LuaTeX.
9 % LuaTeX is free software; you can redistribute it and/or modify it under
10 % the terms of the GNU General Public License as published by the Free
11 % Software Foundation; either version 2 of the License, or (at your
12 % option) any later version.
14 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
15 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 % License for more details.
19 % You should have received a copy of the GNU General Public License along
20 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
22 @* Subsetting glyf, updating loca, hmtx, etc.
24 @ @c
27 #include "ptexlib.h"
29 #include "font/sfnt.h"
30 #include "font/tt_table.h"
31 #include "font/tt_glyf.h"
32 #include "font/writettf.h"
34 @ @c
35 #define NUM_GLYPH_LIMIT 65534
36 #define TABLE_DATA_ALLOC_SIZE 40960
37 #define GLYPH_ARRAY_ALLOC_SIZE 256
39 static USHORT find_empty_slot(struct tt_glyphs *g)
41 USHORT gid;
43 ASSERT(g);
45 for (gid = 0; gid < NUM_GLYPH_LIMIT; gid++) {
46 if (!(g->used_slot[gid / 8] & (1 << (7 - (gid % 8)))))
47 break;
49 if (gid == NUM_GLYPH_LIMIT)
50 normal_error("ttf","no empty glyph slot available.");
52 return gid;
55 USHORT tt_find_glyph(struct tt_glyphs * g, USHORT gid)
57 USHORT idx, new_gid = 0;
59 ASSERT(g);
61 for (idx = 0; idx < g->num_glyphs; idx++) {
62 if (gid == g->gd[idx].ogid) {
63 new_gid = g->gd[idx].gid;
64 break;
68 return new_gid;
71 USHORT tt_get_index(struct tt_glyphs * g, USHORT gid)
73 USHORT idx;
75 ASSERT(g);
77 for (idx = 0; idx < g->num_glyphs; idx++) {
78 if (gid == g->gd[idx].gid)
79 break;
81 if (idx == g->num_glyphs)
82 idx = 0;
84 return idx;
87 USHORT tt_add_glyph(struct tt_glyphs * g, USHORT gid, USHORT new_gid)
89 ASSERT(g);
91 if (g->used_slot[new_gid / 8] & (1 << (7 - (new_gid % 8)))) {
92 formatted_warning("ttf","slot %u already used", new_gid);
93 } else {
94 if (g->num_glyphs + 1 >= NUM_GLYPH_LIMIT)
95 normal_error("ttf","too many glyphs");
97 if (g->num_glyphs >= g->max_glyphs) {
98 g->max_glyphs = (USHORT) (g->max_glyphs + GLYPH_ARRAY_ALLOC_SIZE);
99 g->gd = RENEW(g->gd, g->max_glyphs, struct tt_glyph_desc);
101 g->gd[g->num_glyphs].gid = new_gid;
102 g->gd[g->num_glyphs].ogid = gid;
103 g->gd[g->num_glyphs].length = 0;
104 g->gd[g->num_glyphs].data = NULL;
105 g->used_slot[new_gid / 8] =
106 (unsigned char) (g->used_slot[new_gid /
107 8] | (1 << (7 - (new_gid % 8))));
108 g->num_glyphs++;
111 if (new_gid > g->last_gid) {
112 g->last_gid = new_gid;
115 return new_gid;
119 @ Initialization
121 struct tt_glyphs *tt_build_init(void)
123 struct tt_glyphs *g;
125 g = NEW(1, struct tt_glyphs);
127 g->num_glyphs = 0;
128 g->max_glyphs = 0;
129 g->last_gid = 0;
130 g->emsize = 1;
131 g->default_advh = 0;
132 g->default_tsb = 0;
133 g->gd = NULL;
134 g->used_slot = NEW(8192, unsigned char);
135 memset(g->used_slot, 0, 8192);
136 tt_add_glyph(g, 0, 0);
138 return g;
141 void tt_build_finish(struct tt_glyphs *g)
143 if (g) {
144 if (g->gd) {
145 USHORT idx;
146 for (idx = 0; idx < g->num_glyphs; idx++) {
147 if (g->gd[idx].data)
148 RELEASE(g->gd[idx].data);
150 RELEASE(g->gd);
152 if (g->used_slot)
153 RELEASE(g->used_slot);
154 RELEASE(g);
158 static int glyf_cmp(const void *v1, const void *v2)
160 int cmp = 0;
161 const struct tt_glyph_desc *sv1, *sv2;
163 sv1 = (const struct tt_glyph_desc *) v1;
164 sv2 = (const struct tt_glyph_desc *) v2;
166 if (sv1->gid == sv2->gid)
167 cmp = 0;
168 else if (sv1->gid < sv2->gid)
169 cmp = -1;
170 else
171 cmp = 1;
173 return cmp;
176 @ @c
177 int tt_build_tables(sfnt * sfont, struct tt_glyphs *g)
179 char *hmtx_table_data = NULL, *loca_table_data = NULL;
180 char *glyf_table_data = NULL;
181 ULONG hmtx_table_size, loca_table_size, glyf_table_size;
182 /* some information available from other TrueType table */
183 struct tt_head_table *head = NULL;
184 struct tt_hhea_table *hhea = NULL;
185 struct tt_maxp_table *maxp = NULL;
186 struct tt_longMetrics *hmtx, *vmtx = NULL;
187 struct tt_os2__table *os2;
188 /* temp */
189 ULONG *location, offset;
190 long i;
191 USHORT *w_stat; /* Estimate most frequently appeared width */
193 ASSERT(g);
195 if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
196 normal_error("ttf","invalid font type");
198 if (g->num_glyphs > NUM_GLYPH_LIMIT)
199 normal_error("ttf","too many glyphs");
202 Read head, hhea, maxp, loca:
204 unitsPerEm --> head
206 numHMetrics --> hhea
208 indexToLocFormat --> head
210 numGlyphs --> maxp
212 head = tt_read_head_table(sfont);
213 hhea = tt_read_hhea_table(sfont);
214 maxp = tt_read_maxp_table(sfont);
216 if (hhea->metricDataFormat != 0)
217 normal_error("ttf","unknown metricDataFormat");
219 g->emsize = head->unitsPerEm;
221 sfnt_locate_table(sfont, "hmtx");
222 hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
224 os2 = tt_read_os2__table(sfont);
225 if (os2) {
226 g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
227 g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
229 /* dvipdfmx does this elsewhere! */
230 fd_cur->font_dim[STEMV_CODE].val =
231 (os2->usWeightClass / 65) * (os2->usWeightClass / 65) + 50;
234 if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
235 struct tt_vhea_table *vhea;
236 vhea = tt_read_vhea_table(sfont);
237 sfnt_locate_table(sfont, "vmtx");
238 vmtx =
239 tt_read_longMetrics(sfont, maxp->numGlyphs,
240 vhea->numOfLongVerMetrics);
241 RELEASE(vhea);
242 } else {
243 vmtx = NULL;
246 sfnt_locate_table(sfont, "loca");
247 location = NEW(maxp->numGlyphs + 1, ULONG);
248 if (head->indexToLocFormat == 0) {
249 for (i = 0; i <= maxp->numGlyphs; i++)
250 location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
251 } else if (head->indexToLocFormat == 1) {
252 for (i = 0; i <= maxp->numGlyphs; i++)
253 location[i] = sfnt_get_ulong(sfont);
254 } else {
255 normal_error("ttf","unknown IndexToLocFormat");
258 w_stat = NEW(g->emsize + 2, USHORT);
259 memset(w_stat, 0,
260 (size_t) (sizeof(USHORT) * ((long unsigned) g->emsize + 2)));
262 * Read glyf table.
264 offset = sfnt_locate_table(sfont, "glyf");
266 The |num_glyphs| may grow when composite glyph is found.
267 A component of glyph refered by a composite glyph is appended
268 to |used_glyphs| if it is not already registered in |used_glyphs|.
269 Glyph programs of composite glyphs are modified so that it
270 correctly refer to new gid of their components.
272 for (i = 0; i < NUM_GLYPH_LIMIT; i++) {
273 USHORT gid; /* old gid */
274 ULONG loc, len;
275 BYTE *p, *endptr;
276 SHORT number_of_contours;
278 if (i >= g->num_glyphs) /* finished */
279 break;
281 gid = g->gd[i].ogid;
282 if (gid >= maxp->numGlyphs)
283 formatted_error("ttf","invalid glyph index (gid %u)", gid);
285 loc = location[gid];
286 len = location[gid + 1] - loc;
287 g->gd[i].advw = hmtx[gid].advance;
288 g->gd[i].lsb = hmtx[gid].sideBearing;
289 if (vmtx) {
290 g->gd[i].advh = vmtx[gid].advance;
291 g->gd[i].tsb = vmtx[gid].sideBearing;
292 } else {
293 g->gd[i].advh = g->default_advh;
294 g->gd[i].tsb = g->default_tsb;
296 g->gd[i].length = len;
297 g->gd[i].data = NULL;
298 if (g->gd[i].advw <= g->emsize) {
299 w_stat[g->gd[i].advw]++;
300 } else {
301 w_stat[g->emsize + 1]++; /* larger than em */
304 if (len == 0) { /* Does not contains any data. */
305 continue;
306 } else if (len < 10) {
307 formatted_error("ttf","invalid glyph data (gid %u)", gid);
310 g->gd[i].data = p = NEW(len, BYTE);
311 endptr = p + len;
313 sfnt_seek_set(sfont, (long) (offset + loc));
314 number_of_contours = sfnt_get_short(sfont);
315 p += sfnt_put_short(p, number_of_contours);
317 /* BoundingBox: FWord x 4 */
318 g->gd[i].llx = sfnt_get_short(sfont);
319 g->gd[i].lly = sfnt_get_short(sfont);
320 g->gd[i].urx = sfnt_get_short(sfont);
321 g->gd[i].ury = sfnt_get_short(sfont);
322 /* |_FIXME_| */
323 #if 1
324 if (!vmtx) /* |vertOriginY == sTypeAscender| */
325 g->gd[i].tsb =
326 (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
327 #endif
328 p += sfnt_put_short(p, g->gd[i].llx);
329 p += sfnt_put_short(p, g->gd[i].lly);
330 p += sfnt_put_short(p, g->gd[i].urx);
331 p += sfnt_put_short(p, g->gd[i].ury);
333 /* Read evrything else. */
334 sfnt_read(p, (int) len - 10, sfont);
336 Fix GIDs of composite glyphs.
338 if (number_of_contours < 0) {
339 USHORT flags, cgid, new_gid; /* flag, gid of a component */
340 do {
341 if (p >= endptr)
342 formatted_error("ttf","invalid glyph data (gid %u): %u bytes", gid, (unsigned int) len);
344 * Flags and gid of component glyph are both USHORT.
346 flags = (USHORT) (((*p) << 8) | *(p + 1));
347 p += 2;
348 cgid = (USHORT) (((*p) << 8) | *(p + 1));
349 if (cgid >= maxp->numGlyphs) {
350 formatted_error("ttf","invalid gid (%u > %u) in composite glyph %u", cgid, maxp->numGlyphs, gid);
352 new_gid = tt_find_glyph(g, cgid);
353 if (new_gid == 0) {
354 new_gid = tt_add_glyph(g, cgid, find_empty_slot(g));
356 p += sfnt_put_ushort(p, new_gid);
358 * Just skip remaining part.
360 p += (flags & ARG_1_AND_2_ARE_WORDS) ? 4 : 2;
361 if (flags & WE_HAVE_A_SCALE) /* F2Dot14 */
362 p += 2;
363 else if (flags & WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 2 */
364 p += 4;
365 else if (flags & WE_HAVE_A_TWO_BY_TWO) /* F2Dot14 x 4 */
366 p += 8;
367 } while (flags & MORE_COMPONENTS);
369 TrueType instructions comes here:
371 |length_of_instruction| (|ushort|)
373 instruction (|byte * length_of_instruction|)
377 RELEASE(location);
378 RELEASE(hmtx);
379 if (vmtx)
380 RELEASE(vmtx);
383 int max_count = -1;
385 g->dw = g->gd[0].advw;
386 for (i = 0; i < g->emsize + 1; i++) {
387 if (w_stat[i] > max_count) {
388 max_count = w_stat[i];
389 g->dw = (USHORT) i;
393 RELEASE(w_stat);
395 qsort(g->gd, g->num_glyphs, sizeof(struct tt_glyph_desc), glyf_cmp);
397 USHORT prev, last_advw;
398 char *p, *q;
399 int padlen, num_hm_known;
401 glyf_table_size = 0UL;
402 num_hm_known = 0;
403 last_advw = g->gd[g->num_glyphs - 1].advw;
404 for (i = g->num_glyphs - 1; i >= 0; i--) {
405 padlen =
406 (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
407 glyf_table_size += (ULONG) (g->gd[i].length + (ULONG) padlen);
408 if (!num_hm_known && last_advw != g->gd[i].advw) {
409 hhea->numberOfHMetrics = (USHORT) (g->gd[i].gid + 2);
410 num_hm_known = 1;
413 /* All advance widths are same. */
414 if (!num_hm_known) {
415 hhea->numberOfHMetrics = 1;
417 hmtx_table_size =
418 (ULONG) (hhea->numberOfHMetrics * 2 + (g->last_gid + 1) * 2);
421 Choosing short format does not always give good result
422 when compressed. Sometimes increases size.
424 if (glyf_table_size < 0x20000UL) {
425 head->indexToLocFormat = 0;
426 loca_table_size = (ULONG) ((g->last_gid + 2) * 2);
427 } else {
428 head->indexToLocFormat = 1;
429 loca_table_size = (ULONG) ((g->last_gid + 2) * 4);
432 hmtx_table_data = p = NEW(hmtx_table_size, char);
433 loca_table_data = q = NEW(loca_table_size, char);
434 glyf_table_data = NEW(glyf_table_size, char);
436 offset = 0UL;
437 prev = 0;
438 for (i = 0; i < g->num_glyphs; i++) {
439 long gap, j;
440 gap = (long) g->gd[i].gid - prev - 1;
441 for (j = 1; j <= gap; j++) {
442 if (prev + j == hhea->numberOfHMetrics - 1) {
443 p += sfnt_put_ushort(p, last_advw);
444 } else if (prev + j < hhea->numberOfHMetrics) {
445 p += sfnt_put_ushort(p, 0);
447 p += sfnt_put_short(p, 0);
448 if (head->indexToLocFormat == 0) {
449 q += sfnt_put_ushort(q, (USHORT) (offset / 2));
450 } else {
451 q += sfnt_put_ulong(q, (LONG) offset);
454 padlen =
455 (int) ((g->gd[i].length % 4) ? (4 - (g->gd[i].length % 4)) : 0);
456 if (g->gd[i].gid < hhea->numberOfHMetrics) {
457 p += sfnt_put_ushort(p, g->gd[i].advw);
459 p += sfnt_put_short(p, g->gd[i].lsb);
460 if (head->indexToLocFormat == 0) {
461 q += sfnt_put_ushort(q, (USHORT) (offset / 2));
462 } else {
463 q += sfnt_put_ulong(q, (LONG) offset);
465 memset(glyf_table_data + offset, 0,
466 (size_t) (g->gd[i].length + (ULONG) padlen));
467 memcpy(glyf_table_data + offset, g->gd[i].data, g->gd[i].length);
468 offset += (g->gd[i].length + (ULONG) padlen);
469 prev = g->gd[i].gid;
470 /* free data here since it consume much memory */
471 RELEASE(g->gd[i].data);
472 g->gd[i].length = 0;
473 g->gd[i].data = NULL;
475 if (head->indexToLocFormat == 0) {
476 q += sfnt_put_ushort(q, (USHORT) (offset / 2));
477 } else {
478 q += sfnt_put_ulong(q, (LONG) offset);
481 sfnt_set_table(sfont, "hmtx", (char *) hmtx_table_data,
482 hmtx_table_size);
483 sfnt_set_table(sfont, "loca", (char *) loca_table_data,
484 loca_table_size);
485 sfnt_set_table(sfont, "glyf", (char *) glyf_table_data,
486 glyf_table_size);
489 head->checkSumAdjustment = 0;
490 maxp->numGlyphs = (USHORT) (g->last_gid + 1);
492 /* TODO */
493 sfnt_set_table(sfont, "maxp", tt_pack_maxp_table(maxp), TT_MAXP_TABLE_SIZE);
494 sfnt_set_table(sfont, "hhea", tt_pack_hhea_table(hhea), TT_HHEA_TABLE_SIZE);
495 sfnt_set_table(sfont, "head", tt_pack_head_table(head), TT_HEAD_TABLE_SIZE);
496 RELEASE(maxp);
497 RELEASE(hhea);
498 RELEASE(head);
499 if (os2)
500 RELEASE(os2);
502 return 0;
505 int tt_get_metrics(sfnt * sfont, struct tt_glyphs *g)
507 struct tt_head_table *head = NULL;
508 struct tt_hhea_table *hhea = NULL;
509 struct tt_maxp_table *maxp = NULL;
510 struct tt_longMetrics *hmtx, *vmtx = NULL;
511 struct tt_os2__table *os2;
512 /* temp */
513 ULONG *location, offset;
514 long i;
515 USHORT *w_stat;
517 ASSERT(g);
519 if (sfont == NULL ||
520 #ifdef XETEX
521 sfont->ft_face == NULL
522 #elif defined(pdfTeX)
523 sfont->buffer == NULL
524 #else
525 sfont->stream == NULL
526 #endif
528 normal_error("ttf","file not opened");
530 if (sfont->type != SFNT_TYPE_TRUETYPE && sfont->type != SFNT_TYPE_TTC)
531 normal_error("ttf","invalid font type");
534 Read head, hhea, maxp, loca:
536 unitsPerEm --> head
538 numHMetrics --> hhea
540 indexToLocFormat --> head
542 numGlyphs --> maxp
544 head = tt_read_head_table(sfont);
545 hhea = tt_read_hhea_table(sfont);
546 maxp = tt_read_maxp_table(sfont);
548 if (hhea->metricDataFormat != 0)
549 normal_error("ttf","unknown metricDataFormat");
551 g->emsize = head->unitsPerEm;
553 sfnt_locate_table(sfont, "hmtx");
554 hmtx = tt_read_longMetrics(sfont, maxp->numGlyphs, hhea->numberOfHMetrics);
556 os2 = tt_read_os2__table(sfont);
557 g->default_advh = (USHORT) (os2->sTypoAscender - os2->sTypoDescender);
558 g->default_tsb = (SHORT) (g->default_advh - os2->sTypoAscender);
560 if (sfnt_find_table_pos(sfont, "vmtx") > 0) {
561 struct tt_vhea_table *vhea;
562 vhea = tt_read_vhea_table(sfont);
563 sfnt_locate_table(sfont, "vmtx");
564 vmtx =
565 tt_read_longMetrics(sfont, maxp->numGlyphs,
566 vhea->numOfLongVerMetrics);
567 RELEASE(vhea);
568 } else {
569 vmtx = NULL;
572 sfnt_locate_table(sfont, "loca");
573 location = NEW(maxp->numGlyphs + 1, ULONG);
574 if (head->indexToLocFormat == 0) {
575 for (i = 0; i <= maxp->numGlyphs; i++)
576 location[i] = 2 * ((ULONG) sfnt_get_ushort(sfont));
577 } else if (head->indexToLocFormat == 1) {
578 for (i = 0; i <= maxp->numGlyphs; i++)
579 location[i] = sfnt_get_ulong(sfont);
580 } else {
581 normal_error("ttf","inknown IndexToLocFormat");
584 w_stat = NEW(g->emsize + 2, USHORT);
585 memset(w_stat, 0, (size_t) ((int) sizeof(USHORT) * (g->emsize + 2)));
587 Read glyf table.
589 offset = sfnt_locate_table(sfont, "glyf");
590 for (i = 0; i < g->num_glyphs; i++) {
591 USHORT gid; /* old gid */
592 ULONG loc, len;
593 /*SHORT number_of_contours;*/
595 gid = g->gd[i].ogid;
596 if (gid >= maxp->numGlyphs)
597 formatted_error("ttf","invalid glyph index (gid %u)", gid);
599 loc = location[gid];
600 len = location[gid + 1] - loc;
601 g->gd[i].advw = hmtx[gid].advance;
602 g->gd[i].lsb = hmtx[gid].sideBearing;
603 if (vmtx) {
604 g->gd[i].advh = vmtx[gid].advance;
605 g->gd[i].tsb = vmtx[gid].sideBearing;
606 } else {
607 g->gd[i].advh = g->default_advh;
608 g->gd[i].tsb = g->default_tsb;
610 g->gd[i].length = len;
611 g->gd[i].data = NULL;
613 if (g->gd[i].advw <= g->emsize) {
614 w_stat[g->gd[i].advw]++;
615 } else {
616 w_stat[g->emsize + 1]++; /* larger than em */
619 if (len == 0) { /* Does not contains any data. */
620 continue;
621 } else if (len < 10) {
622 formatted_error("ttf","invalid glyph data (gid %u)", gid);
625 sfnt_seek_set(sfont, (long) (offset + loc));
626 /*number_of_contours = */(void)sfnt_get_short(sfont);
628 /* BoundingBox: FWord x 4 */
629 g->gd[i].llx = sfnt_get_short(sfont);
630 g->gd[i].lly = sfnt_get_short(sfont);
631 g->gd[i].urx = sfnt_get_short(sfont);
632 g->gd[i].ury = sfnt_get_short(sfont);
633 /* |_FIXME_| */
634 #if 1
635 if (!vmtx) /* |vertOriginY == sTypeAscender| */
636 g->gd[i].tsb =
637 (SHORT) (g->default_advh - g->default_tsb - g->gd[i].ury);
638 #endif
640 RELEASE(location);
641 RELEASE(hmtx);
642 RELEASE(maxp);
643 RELEASE(hhea);
644 RELEASE(head);
645 RELEASE(os2);
647 if (vmtx)
648 RELEASE(vmtx);
651 int max_count = -1;
653 g->dw = g->gd[0].advw;
654 for (i = 0; i < g->emsize + 1; i++) {
655 if (w_stat[i] > max_count) {
656 max_count = w_stat[i];
657 g->dw = (USHORT) i;
661 RELEASE(w_stat);
664 return 0;