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.
29 #include
"font/sfnt.h"
30 #include
"font/tt_table.h"
31 #include
"font/tt_glyf.h"
32 #include
"font/writettf.h"
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
)
45 for
(gid
= 0; gid
< NUM_GLYPH_LIMIT
; gid
++) {
46 if
(!(g-
>used_slot
[gid
/ 8] & (1 << (7 - (gid % 8)))))
49 if
(gid
== NUM_GLYPH_LIMIT
)
50 normal_error
("ttf","no empty glyph slot available.");
55 USHORT tt_find_glyph
(struct tt_glyphs
* g
, USHORT gid
)
57 USHORT idx
, new_gid
= 0;
61 for
(idx
= 0; idx
< g-
>num_glyphs
; idx
++) {
62 if
(gid
== g-
>gd
[idx
].ogid
) {
63 new_gid
= g-
>gd
[idx
].gid
;
71 USHORT tt_get_index
(struct tt_glyphs
* g
, USHORT gid
)
77 for
(idx
= 0; idx
< g-
>num_glyphs
; idx
++) {
78 if
(gid
== g-
>gd
[idx
].gid
)
81 if
(idx
== g-
>num_glyphs
)
87 USHORT tt_add_glyph
(struct tt_glyphs
* g
, USHORT gid
, USHORT new_gid
)
91 if
(g-
>used_slot
[new_gid
/ 8] & (1 << (7 - (new_gid % 8)))) {
92 formatted_warning
("ttf","slot %u already used", new_gid
);
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))));
111 if
(new_gid
> g-
>last_gid
) {
112 g-
>last_gid
= new_gid
;
121 struct tt_glyphs
*tt_build_init
(void
)
125 g
= NEW(1, struct tt_glyphs
);
134 g-
>used_slot
= NEW(8192, unsigned char
);
135 memset
(g-
>used_slot
, 0, 8192);
136 tt_add_glyph
(g
, 0, 0);
141 void tt_build_finish
(struct tt_glyphs
*g
)
146 for
(idx
= 0; idx
< g-
>num_glyphs
; idx
++) {
148 RELEASE(g-
>gd
[idx
].data
);
153 RELEASE(g-
>used_slot
);
158 static int glyf_cmp
(const void
*v1
, const void
*v2
)
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
)
168 else if
(sv1-
>gid
< sv2-
>gid
)
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
;
189 ULONG
*location
, offset
;
191 USHORT
*w_stat
; /* Estimate most frequently appeared width
*/
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
:
208 indexToLocFormat
--> head
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
);
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");
239 tt_read_longMetrics
(sfont
, maxp-
>numGlyphs
,
240 vhea-
>numOfLongVerMetrics
);
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
);
255 normal_error
("ttf","unknown IndexToLocFormat");
258 w_stat
= NEW(g-
>emsize
+ 2, USHORT
);
260 (size_t
) (sizeof
(USHORT
) * ((long unsigned
) g-
>emsize
+ 2)));
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
*/
276 SHORT number_of_contours
;
278 if
(i
>= g-
>num_glyphs
) /* finished
*/
282 if
(gid
>= maxp-
>numGlyphs
)
283 formatted_error
("ttf","invalid glyph index (gid %u)", gid
);
286 len
= location
[gid
+ 1] - loc
;
287 g-
>gd
[i
].advw
= hmtx
[gid
].advance
;
288 g-
>gd
[i
].lsb
= hmtx
[gid
].sideBearing
;
290 g-
>gd
[i
].advh
= vmtx
[gid
].advance
;
291 g-
>gd
[i
].tsb
= vmtx
[gid
].sideBearing
;
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
]++;
301 w_stat
[g-
>emsize
+ 1]++; /* larger than em
*/
304 if
(len
== 0) { /* Does not contains any data.
*/
306 } else if
(len
< 10) {
307 formatted_error
("ttf","invalid glyph data (gid %u)", gid
);
310 g-
>gd
[i
].data
= p
= NEW(len
, BYTE);
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
);
324 if
(!vmtx
) /* |vertOriginY
== sTypeAscender|
*/
326 (SHORT) (g-
>default_advh
- g-
>default_tsb
- g-
>gd
[i
].ury
);
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
*/
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));
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
);
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 */
363 else if
(flags
& WE_HAVE_AN_X_AND_Y_SCALE) /* F2Dot14 x 2 */
365 else if
(flags
& WE_HAVE_A_TWO_BY_TWO) /* F2Dot14 x 4 */
367 } while
(flags
& MORE_COMPONENTS);
369 TrueType instructions comes here
:
371 |length_of_instruction|
(|ushort|
)
373 instruction
(|byte
* length_of_instruction|
)
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
];
395 qsort
(g-
>gd
, g-
>num_glyphs
, sizeof
(struct tt_glyph_desc
), glyf_cmp
);
397 USHORT prev
, last_advw
;
399 int padlen
, num_hm_known
;
401 glyf_table_size
= 0UL;
403 last_advw
= g-
>gd
[g-
>num_glyphs
- 1].advw
;
404 for
(i
= g-
>num_glyphs
- 1; i
>= 0; i--
) {
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);
413 /* All advance widths are same.
*/
415 hhea-
>numberOfHMetrics
= 1;
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);
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
);
438 for
(i
= 0; i
< g-
>num_glyphs
; i
++) {
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));
451 q
+= sfnt_put_ulong
(q
, (LONG) offset
);
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));
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
);
470 /* free data here since it consume much memory
*/
471 RELEASE(g-
>gd
[i
].data
);
473 g-
>gd
[i
].data
= NULL;
475 if
(head-
>indexToLocFormat
== 0) {
476 q
+= sfnt_put_ushort
(q
, (USHORT
) (offset
/ 2));
478 q
+= sfnt_put_ulong
(q
, (LONG) offset
);
481 sfnt_set_table
(sfont
, "hmtx", (char
*) hmtx_table_data
,
483 sfnt_set_table
(sfont
, "loca", (char
*) loca_table_data
,
485 sfnt_set_table
(sfont
, "glyf", (char
*) glyf_table_data
,
489 head-
>checkSumAdjustment
= 0;
490 maxp-
>numGlyphs
= (USHORT
) (g-
>last_gid
+ 1);
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
);
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
;
513 ULONG
*location
, offset
;
521 sfont-
>ft_face
== NULL
522 #elif defined
(pdfTeX
)
523 sfont-
>buffer
== NULL
525 sfont-
>stream
== NULL
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
:
540 indexToLocFormat
--> head
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");
565 tt_read_longMetrics
(sfont
, maxp-
>numGlyphs
,
566 vhea-
>numOfLongVerMetrics
);
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
);
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)));
589 offset
= sfnt_locate_table
(sfont
, "glyf");
590 for
(i
= 0; i
< g-
>num_glyphs
; i
++) {
591 USHORT gid
; /* old gid
*/
593 /*SHORT number_of_contours
;*/
596 if
(gid
>= maxp-
>numGlyphs
)
597 formatted_error
("ttf","invalid glyph index (gid %u)", gid
);
600 len
= location
[gid
+ 1] - loc
;
601 g-
>gd
[i
].advw
= hmtx
[gid
].advance
;
602 g-
>gd
[i
].lsb
= hmtx
[gid
].sideBearing
;
604 g-
>gd
[i
].advh
= vmtx
[gid
].advance
;
605 g-
>gd
[i
].tsb
= vmtx
[gid
].sideBearing
;
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
]++;
616 w_stat
[g-
>emsize
+ 1]++; /* larger than em
*/
619 if
(len
== 0) { /* Does not contains any data.
*/
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
);
635 if
(!vmtx
) /* |vertOriginY
== sTypeAscender|
*/
637 (SHORT) (g-
>default_advh
- g-
>default_tsb
- g-
>gd
[i
].ury
);
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
];