beta-0.89.2
[luatex.git] / source / texk / web2c / luatexdir / font / writetype2.w
blobd5ce1aca40a1d7295e93646c8a1570c92f5016fd
1 % writetype2.w
3 % Copyright 2006-2012 Taco Hoekwater <taco@@luatex.org>
5 % This file is part of LuaTeX.
7 % LuaTeX is free software; you can redistribute it and/or modify it under
8 % the terms of the GNU General Public License as published by the Free
9 % Software Foundation; either version 2 of the License, or (at your
10 % option) any later version.
12 % LuaTeX is distributed in the hope that it will be useful, but WITHOUT
13 % ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 % FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 % License for more details.
17 % You should have received a copy of the GNU General Public License along
18 % with LuaTeX; if not, see <http://www.gnu.org/licenses/>.
20 @ @c
23 #include "ptexlib.h"
24 #include "font/writettf.h"
25 #include "font/writecff.h"
26 #include "lua/luatex-api.h"
28 #include "font/sfnt.h"
29 #include "font/tt_glyf.h"
31 @ forward declaration
33 boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen);
35 @ @c
36 unsigned long cidtogid_obj = 0;
38 @ low-level helpers
40 #define test_loc(l) \
41 if ((f->loc + l) > f->buflen) { \
42 fprintf(stderr, "File ended prematurely\n"); \
43 uexit(1); \
47 BYTE get_unsigned_byte(sfnt * f)
49 test_loc(1);
50 return (BYTE) f->buffer[(f->loc++)];
53 ICHAR get_signed_byte(sfnt * f)
55 test_loc(1);
56 return (ICHAR) f->buffer[(f->loc++)];
59 USHORT get_unsigned_pair(sfnt * f)
61 USHORT l;
62 test_loc(2);
63 l = f->buffer[(f->loc++)];
64 l = (USHORT) (l * 0x100 + f->buffer[(f->loc++)]);
65 return l;
68 SHORT get_signed_pair(sfnt * f)
70 long l;
71 test_loc(2);
72 l = f->buffer[(f->loc++)];
73 if (l > 0x80)
74 l -= 0x100;
75 l = l * 0x100 + f->buffer[(f->loc++)];
76 return (SHORT) l;
79 ULONG get_unsigned_quad(sfnt * f)
81 ULONG l;
82 test_loc(4);
83 l = f->buffer[(f->loc++)];
84 l = l * 0x100 + f->buffer[(f->loc++)];
85 l = l * 0x100 + f->buffer[(f->loc++)];
86 l = l * 0x100 + f->buffer[(f->loc++)];
87 return l;
90 int do_sfnt_read(unsigned char *dest, int len, sfnt * f)
92 int i;
93 test_loc(len);
94 for (i = 0; i < len; i++) {
95 *(dest + i) = f->buffer[f->loc + i];
97 f->loc += len;
98 return len;
101 pdf_obj *pdf_new_stream(void)
103 pdf_obj *stream = xmalloc(sizeof(pdf_obj));
104 stream->length = 0;
105 stream->data = NULL;
106 return stream;
109 void pdf_add_stream(pdf_obj * stream, unsigned char *buf, long len)
111 int i;
112 assert(stream != NULL);
113 if (stream->data == NULL) {
114 stream->data = xmalloc((unsigned) len);
115 } else {
116 stream->data =
117 xrealloc(stream->data, (unsigned) len + (unsigned) stream->length);
119 for (i = 0; i < len; i++) {
120 *(stream->data + stream->length + i) = *(buf + i);
122 stream->length += (unsigned) len;
125 void pdf_release_obj(pdf_obj * stream)
127 if (stream != NULL) {
128 if (stream->data != NULL) {
129 xfree(stream->data);
131 xfree(stream);
135 @ The main function.
137 boolean writetype2(PDF pdf, fd_entry * fd)
139 int callback_id;
140 int file_opened = 0;
141 boolean ret;
143 glyph_tab = NULL;
145 fd_cur = fd; /* |fd_cur| is global inside \.{writettf.w} */
146 assert(fd_cur->fm != NULL);
147 assert(is_truetype(fd_cur->fm));
148 assert(is_included(fd_cur->fm));
150 ttf_curbyte = 0;
151 ttf_size = 0;
152 cur_file_name =
153 luatex_find_file(fd_cur->fm->ff_name, find_opentype_file_callback);
154 if (cur_file_name == NULL) {
155 formatted_error("type 2","cannot find file '%s'", fd_cur->fm->ff_name);
157 callback_id = callback_defined(read_opentype_file_callback);
158 if (callback_id > 0) {
159 if (run_callback(callback_id, "S->bSd", cur_file_name,
160 &file_opened, &ttf_buffer, &ttf_size) &&
161 file_opened && ttf_size > 0) {
162 } else {
163 formatted_error("type 2","cannot find file '%s'", cur_file_name);
165 } else {
166 if (!otf_open(cur_file_name)) {
167 formatted_error("type 2","cannot find file '%s'", cur_file_name);
169 ttf_read_file();
170 ttf_close();
173 fd_cur->ff_found = true;
175 if (is_subsetted(fd_cur->fm))
176 report_start_file(filetype_subset,cur_file_name);
177 else
178 report_start_file(filetype_font,cur_file_name);
180 /* here is the real work */
182 ret = make_tt_subset(pdf, fd, ttf_buffer, ttf_size);
183 #if 0
184 xfree (dir_tab);
185 #endif
186 xfree(ttf_buffer);
187 if (is_subsetted(fd_cur->fm))
188 report_stop_file(filetype_subset);
189 else
190 report_stop_file(filetype_font);
191 cur_file_name = NULL;
192 return ret;
195 @ PDF viewer applications use following tables (CIDFontType 2)
197 \.{head, hhea, loca, maxp, glyf, hmtx, fpgm, cvt\_, prep}
199 \rightline{from PDF Ref. v.1.3, 2nd ed.}
201 The \.{fpgm}, \.{cvt\_} and \.{prep} tables appears only when TrueType instructions
202 requires them. Those tables must be preserved if they exist.
203 We use |must_exist| flag to indicate `preserve it if present'
204 and to make sure not to cause an error when it does not exist.
206 \.{post} and \.{name} table must exist in ordinary TrueType font file,
207 but when a TrueType font is converted to CIDFontType 2 font, those tables
208 are no longer required.
210 The OS/2 table (required for TrueType font for Windows and OS/2) contains
211 liscencing information, but PDF viewers seems not using them.
213 The \.{name} table added. See comments in \.{writettf.w}.
216 static struct {
217 const char *name;
218 int must_exist;
219 } required_table[] = {
221 "OS/2", 0}, {
222 "cmap", 0}, {
223 "head", 1}, {
224 "hhea", 1}, {
225 "loca", 1}, {
226 "maxp", 0}, {
227 "name", 1}, {
228 "glyf", 1}, {
229 "hmtx", 1}, {
230 "fpgm", 0}, {
231 "cvt ", 0}, {
232 "prep", 0}, {
233 NULL, 0}
237 unsigned long ttc_read_offset(sfnt * sfont, int ttc_idx, fd_entry * fd)
239 /*ULONG version;*/
240 unsigned long offset = 0;
241 unsigned long num_dirs = 0;
243 sfnt_seek_set(sfont, 4); /* skip version tag */
245 /*version = */(void)sfnt_get_ulong(sfont);
246 num_dirs = sfnt_get_ulong(sfont);
247 if (ttc_idx < 0 || ttc_idx > (int) (num_dirs - 1)) {
248 fprintf(stderr, "Invalid TTC index number %i (0..%i), using index 0 for font %s\n",
249 ttc_idx,(int) (num_dirs - 1),(fd->fm->ps_name ? fd->fm->ps_name : ""));
250 return 0 ;
252 sfnt_seek_set(sfont, 12 + ttc_idx * 4);
253 offset = sfnt_get_ulong(sfont);
255 return offset;
258 @ Creating the subset.
260 extern int cidset;
261 boolean make_tt_subset(PDF pdf, fd_entry * fd, unsigned char *buff, int buflen)
264 long i, cid;
265 unsigned int last_cid = 0;
266 glw_entry *found;
267 struct avl_traverser t;
268 unsigned char *cidtogidmap;
269 unsigned short num_glyphs, gid;
270 struct tt_glyphs *glyphs;
271 char *used_chars = NULL;
272 sfnt *sfont;
273 pdf_obj *fontfile;
274 int verbose = 0, error = 0;
276 cidtogidmap = NULL;
278 sfont = sfnt_open(buff, buflen);
280 if (sfont->type == SFNT_TYPE_TTC) {
281 i = ff_get_ttc_index(fd->fm->ff_name, fd->fm->ps_name);
282 error = sfnt_read_table_directory(sfont, ttc_read_offset(sfont, (int) i, fd));
283 } else {
284 error = sfnt_read_table_directory(sfont, 0);
287 if (error < 0) {
288 fprintf(stderr, "Could not parse the ttf directory.\n");
289 uexit(1);
292 if (sfont->type == SFNT_TYPE_TTC && sfnt_find_table_pos(sfont, "CFF ")) {
293 sfnt_close(sfont);
294 return false;
297 if (is_subsetted(fd->fm)) {
298 /* rebuild the glyph tables and create a fresh cidmap */
299 glyphs = tt_build_init();
301 last_cid = 0;
303 avl_t_init(&t, fd->gl_tree);
304 for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
305 found != NULL; found = (glw_entry *) avl_t_next(&t)) {
306 if (found->id > last_cid)
307 last_cid = found->id;
310 #ifndef NO_GHOSTSCRIPT_BUG
311 cidtogidmap = NULL;
312 #else
313 cidtogidmap = xmalloc(((last_cid + 1) * 2) * sizeof(unsigned char));
314 memset(cidtogidmap, 0, (last_cid + 1) * 2);
315 #endif
317 /* fill |used_chars| */
318 used_chars = xmalloc((last_cid + 1) * sizeof(char));
319 memset(used_chars, 0, (last_cid + 1));
320 avl_t_init(&t, fd->gl_tree);
321 for (found = (glw_entry *) avl_t_first(&t, fd->gl_tree);
322 found != NULL; found = (glw_entry *) avl_t_next(&t)) {
323 used_chars[found->id] = 1;
326 /* Map CIDs to GIDs. */
328 num_glyphs = 1; /* \.{.notdef} */
329 for (cid = 1; cid <= (long) last_cid; cid++) {
330 if (used_chars[cid] == 0)
331 continue;
332 gid = (short unsigned) cid;
335 #ifndef NO_GHOSTSCRIPT_BUG
336 gid = tt_add_glyph(glyphs, (USHORT) gid, (USHORT) cid);
337 #else
338 gid = tt_add_glyph(glyphs, (USHORT) gid, (USHORT) num_glyphs);
339 cidtogidmap[2 * cid] = gid >> 8;
340 cidtogidmap[2 * cid + 1] = gid & 0xff;
341 #endif /* |!NO_GHOSTSCRIPT_BUG| */
343 num_glyphs++;
346 if (num_glyphs == 1) {
347 fprintf(stderr, "No glyphs in subset?.\n");
348 uexit(1);
351 if (tt_build_tables(sfont, glyphs) < 0) {
352 fprintf(stderr, "Could not parse the ttf buffer.\n");
353 uexit(1);
356 if (verbose > 1) {
357 fprintf(stdout, "[%u glyphs (Max CID: %u)]", glyphs->num_glyphs,
358 last_cid);
361 tt_build_finish(glyphs);
364 /* Create font file */
366 for (i = 0; required_table[i].name; i++) {
367 if (sfnt_require_table(sfont,
368 required_table[i].name,
369 required_table[i].must_exist) < 0) {
370 fprintf(stderr, "Some required TrueType table does not exist.");
371 uexit(1);
375 fontfile = sfnt_create_FontFile_stream(sfont);
377 if (verbose > 1) {
378 fprintf(stdout, "[%ld bytes]", fontfile->length);
381 /* squeeze in the cidgidmap */
382 if (cidtogidmap != NULL) {
383 cidtogid_obj = (unsigned long) pdf_create_obj(pdf, obj_type_others, 0);
384 pdf_begin_obj(pdf, (int) cidtogid_obj, OBJSTM_NEVER);
385 pdf_begin_dict(pdf);
386 pdf_dict_add_int(pdf, "Length", ((last_cid + 1) * 2));
387 pdf_end_dict(pdf);
388 assert(0); /* code unused */
389 pdf_begin_stream(pdf);
390 pdf_room(pdf, (int) ((last_cid + 1) * 2));
391 for (i = 0; i < ((int) (last_cid + 1) * 2); i++) {
392 pdf_quick_out(pdf, cidtogidmap[i]);
394 pdf_end_stream(pdf);
395 pdf_end_obj(pdf);
398 /* the tff subset */
399 for (i = 0; i < (int) (fontfile->length); i++)
400 strbuf_putchar(pdf->fb, fontfile->data[i]);
402 pdf_release_obj(fontfile);
404 /* CIDSet: a table of bits indexed by cid, bytes with high order bit first,
405 each (set) bit is a (present) CID. */
406 if (is_subsetted(fd->fm)) {
407 cidset = pdf_create_obj(pdf, obj_type_others, 0);
408 if (cidset != 0) {
409 size_t l = (last_cid / 8) + 1;
410 char *stream = xmalloc(l);
411 memset(stream, 0, l);
412 for (cid = 1; cid <= (long) last_cid; cid++) {
413 if (used_chars[cid]) {
414 stream[(cid / 8)] |= (1 << (7 - (cid % 8)));
417 pdf_begin_obj(pdf, cidset, OBJSTM_NEVER);
418 pdf_begin_dict(pdf);
419 pdf_dict_add_streaminfo(pdf);
420 pdf_end_dict(pdf);
421 pdf_begin_stream(pdf);
422 pdf_out_block(pdf, stream, l);
423 pdf_end_stream(pdf);
424 pdf_end_obj(pdf);
428 /* TODO other stuff that needs fixing: */
430 /* DW, W, DW2, and W2 */
431 #if 0
432 if (opt_flags & CIDFONT_FORCE_FIXEDPITCH) {
433 pdf_add_dict(font->fontdict,
434 pdf_new_name("DW"), pdf_new_number(1000.0));
435 } else {
436 add_TTCIDHMetrics(font->fontdict, glyphs, used_chars, cidtogidmap,
437 last_cid);
438 if (v_used_chars)
439 add_TTCIDVMetrics(font->fontdict, glyphs, used_chars, cidtogidmap,
440 last_cid);
442 #endif
444 xfree(used_chars);
445 sfnt_close(sfont);
446 return true;