1#include "mupdf/fitz.h"
2#include "mupdf/pdf.h"
3
4#include "../fitz/fitz-imp.h"
5
6#include <ft2build.h>
7#include FT_FREETYPE_H
8#ifdef FT_FONT_FORMATS_H
9#include FT_FONT_FORMATS_H
10#else
11#include FT_XFREE86_H
12#endif
13#include FT_TRUETYPE_TABLES_H
14
15#ifndef FT_SFNT_HEAD
16#define FT_SFNT_HEAD ft_sfnt_head
17#endif
18
19static int ft_font_file_kind(FT_Face face)
20{
21#ifdef FT_FONT_FORMATS_H
22 const char *kind = FT_Get_Font_Format(face);
23#else
24 const char *kind = FT_Get_X11_Font_Format(face);
25#endif
26 if (!strcmp(kind, "TrueType")) return 2;
27 if (!strcmp(kind, "Type 1")) return 1;
28 if (!strcmp(kind, "CFF")) return 3;
29 if (!strcmp(kind, "CID Type 1")) return 1;
30 return 0;
31}
32
33static int is_ttc(fz_font *font)
34{
35 return !memcmp(font->buffer->data, "ttcf", 4);
36}
37
38static int is_truetype(FT_Face face)
39{
40 return ft_font_file_kind(face) == 2;
41}
42
43static int is_postscript(FT_Face face)
44{
45 int kind = ft_font_file_kind(face);
46 return (kind == 1 || kind == 3);
47}
48
49static int is_builtin_font(fz_context *ctx, fz_font *font)
50{
51 int size;
52 unsigned char *data;
53 if (!font->buffer)
54 return 0;
55 fz_buffer_storage(ctx, font->buffer, &data);
56 return fz_lookup_base14_font(ctx, pdf_clean_font_name(font->name), &size) == data;
57}
58
59static pdf_obj*
60pdf_add_font_file(fz_context *ctx, pdf_document *doc, fz_font *font)
61{
62 fz_buffer *buf = font->buffer;
63 pdf_obj *obj = NULL;
64 pdf_obj *ref = NULL;
65
66 fz_var(obj);
67 fz_var(ref);
68
69 /* Check for substitute fonts */
70 if (font->flags.ft_substitute)
71 return NULL;
72
73 fz_try(ctx)
74 {
75 size_t len = fz_buffer_storage(ctx, buf, NULL);
76 obj = pdf_new_dict(ctx, doc, 3);
77 pdf_dict_put_int(ctx, obj, PDF_NAME(Length1), (int)len);
78 switch (ft_font_file_kind(font->ft_face))
79 {
80 case 1:
81 /* TODO: these may not be the correct values, but I doubt it matters */
82 pdf_dict_put_int(ctx, obj, PDF_NAME(Length2), len);
83 pdf_dict_put_int(ctx, obj, PDF_NAME(Length3), 0);
84 break;
85 case 2:
86 break;
87 case 3:
88 if (FT_Get_Sfnt_Table(font->ft_face, FT_SFNT_HEAD))
89 pdf_dict_put(ctx, obj, PDF_NAME(Subtype), PDF_NAME(OpenType));
90 else
91 pdf_dict_put(ctx, obj, PDF_NAME(Subtype), PDF_NAME(Type1C));
92 break;
93 }
94 ref = pdf_add_object(ctx, doc, obj);
95 pdf_update_stream(ctx, doc, ref, buf, 0);
96 }
97 fz_always(ctx)
98 {
99 pdf_drop_obj(ctx, obj);
100 }
101 fz_catch(ctx)
102 {
103 pdf_drop_obj(ctx, ref);
104 fz_rethrow(ctx);
105 }
106 return ref;
107}
108
109static void
110pdf_add_font_descriptor(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font)
111{
112 FT_Face face = font->ft_face;
113 pdf_obj *fdobj = NULL;
114 pdf_obj *fileref;
115 fz_rect bbox;
116
117 fdobj = pdf_new_dict(ctx, doc, 10);
118 fz_try(ctx)
119 {
120 pdf_dict_put(ctx, fdobj, PDF_NAME(Type), PDF_NAME(FontDescriptor));
121 pdf_dict_put_name(ctx, fdobj, PDF_NAME(FontName), font->name);
122
123 bbox.x0 = font->bbox.x0 * 1000;
124 bbox.y0 = font->bbox.y0 * 1000;
125 bbox.x1 = font->bbox.x1 * 1000;
126 bbox.y1 = font->bbox.y1 * 1000;
127 pdf_dict_put_rect(ctx, fdobj, PDF_NAME(FontBBox), bbox);
128
129 pdf_dict_put_int(ctx, fdobj, PDF_NAME(ItalicAngle), 0);
130 pdf_dict_put_int(ctx, fdobj, PDF_NAME(Ascent), face->ascender * 1000.0f / face->units_per_EM);
131 pdf_dict_put_int(ctx, fdobj, PDF_NAME(Descent), face->descender * 1000.0f / face->units_per_EM);
132 pdf_dict_put_int(ctx, fdobj, PDF_NAME(StemV), 80);
133 pdf_dict_put_int(ctx, fdobj, PDF_NAME(Flags), PDF_FD_NONSYMBOLIC);
134
135 fileref = pdf_add_font_file(ctx, doc, font);
136 if (fileref)
137 {
138 switch (ft_font_file_kind(face))
139 {
140 default:
141 case 1: pdf_dict_put_drop(ctx, fdobj, PDF_NAME(FontFile), fileref); break;
142 case 2: pdf_dict_put_drop(ctx, fdobj, PDF_NAME(FontFile2), fileref); break;
143 case 3: pdf_dict_put_drop(ctx, fdobj, PDF_NAME(FontFile3), fileref); break;
144 }
145 }
146
147 pdf_dict_put_drop(ctx, fobj, PDF_NAME(FontDescriptor), pdf_add_object(ctx, doc, fdobj));
148 }
149 fz_always(ctx)
150 pdf_drop_obj(ctx, fdobj);
151 fz_catch(ctx)
152 fz_rethrow(ctx);
153}
154
155static void
156pdf_add_simple_font_widths(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font, const char * const encoding[])
157{
158 int width_table[256];
159 pdf_obj *widths;
160 int i, first, last;
161
162 first = 0;
163 last = 0;
164
165 for (i = 0; i < 256; ++i)
166 {
167 int glyph = 0;
168 if (encoding[i])
169 {
170 glyph = fz_encode_character_by_glyph_name(ctx, font, encoding[i]);
171 }
172 if (glyph > 0)
173 {
174 if (!first)
175 first = i;
176 last = i;
177 width_table[i] = fz_advance_glyph(ctx, font, glyph, 0) * 1000;
178 }
179 else
180 width_table[i] = 0;
181 }
182
183 widths = pdf_new_array(ctx, doc, last - first + 1);
184 pdf_dict_put_drop(ctx, fobj, PDF_NAME(Widths), widths);
185 for (i = first; i <= last; ++i)
186 pdf_array_push_int(ctx, widths, width_table[i]);
187 pdf_dict_put_int(ctx, fobj, PDF_NAME(FirstChar), first);
188 pdf_dict_put_int(ctx, fobj, PDF_NAME(LastChar), last);
189}
190
191static void
192pdf_add_cid_system_info(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, const char *reg, const char *ord, int supp)
193{
194 pdf_obj *csi = pdf_dict_put_dict(ctx, fobj, PDF_NAME(CIDSystemInfo), 3);
195 pdf_dict_put_string(ctx, csi, PDF_NAME(Registry), reg, strlen(reg));
196 pdf_dict_put_string(ctx, csi, PDF_NAME(Ordering), ord, strlen(ord));
197 pdf_dict_put_int(ctx, csi, PDF_NAME(Supplement), supp);
198}
199
200/* Different states of starting, same width as last, or consecutive glyph */
201enum { FW_START, FW_SAME, FW_RUN };
202
203/* ToDo: Ignore the default sized characters */
204static void
205pdf_add_cid_font_widths(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font)
206{
207 FT_Face face = font->ft_face;
208 pdf_obj *run_obj = NULL;
209 pdf_obj *fw;
210 int curr_code;
211 int prev_code;
212 int curr_size;
213 int prev_size;
214 int first_code;
215 int new_first_code;
216 int state = FW_START;
217 int new_state = FW_START;
218 int publish = 0;
219
220 fz_var(run_obj);
221
222 fw = pdf_add_new_array(ctx, doc, 10);
223 fz_try(ctx)
224 {
225 prev_code = 0;
226 prev_size = fz_advance_glyph(ctx, font, 0, 0) * 1000;
227 first_code = prev_code;
228
229 for (;;)
230 {
231 curr_code = prev_code + 1;
232 if (curr_code >= face->num_glyphs)
233 break;
234 curr_size = fz_advance_glyph(ctx, font, curr_code, 0) * 1000;
235
236 switch (state)
237 {
238 case FW_SAME:
239 if (curr_size != prev_size)
240 {
241 /* End of same widths for consecutive ids. Current will
242 * be pushed as prev. below during next iteration */
243 publish = 1;
244 if (curr_code < face->num_glyphs)
245 run_obj = pdf_new_array(ctx, doc, 10);
246 new_state = FW_RUN;
247 /* And the new first code is our current code */
248 new_first_code = curr_code;
249 }
250 break;
251 case FW_RUN:
252 if (curr_size == prev_size)
253 {
254 /* Same width, so start a new same entry starting with
255 * the previous code. i.e. the prev size is not put
256 * in the run */
257 publish = 1;
258 new_state = FW_SAME;
259 new_first_code = prev_code;
260 }
261 else
262 {
263 /* Add prev size to run_obj */
264 pdf_array_push_int(ctx, run_obj, prev_size);
265 }
266 break;
267 case FW_START:
268 /* Starting fresh. Determine our state */
269 if (curr_size == prev_size)
270 {
271 state = FW_SAME;
272 }
273 else
274 {
275 run_obj = pdf_new_array(ctx, doc, 10);
276 pdf_array_push_int(ctx, run_obj, prev_size);
277 state = FW_RUN;
278 }
279 new_first_code = prev_code;
280 break;
281 }
282
283 if (publish || curr_code == face->num_glyphs)
284 {
285 switch (state)
286 {
287 case FW_SAME:
288 /* Add three entries. First cid, last cid and width */
289 pdf_array_push_int(ctx, fw, first_code);
290 pdf_array_push_int(ctx, fw, prev_code);
291 pdf_array_push_int(ctx, fw, prev_size);
292 break;
293 case FW_RUN:
294 if (pdf_array_len(ctx, run_obj) > 0)
295 {
296 pdf_array_push_int(ctx, fw, first_code);
297 pdf_array_push(ctx, fw, run_obj);
298 }
299 pdf_drop_obj(ctx, run_obj);
300 run_obj = NULL;
301 break;
302 case FW_START:
303 /* Lone wolf. Not part of a consecutive run */
304 pdf_array_push_int(ctx, fw, prev_code);
305 pdf_array_push_int(ctx, fw, prev_code);
306 pdf_array_push_int(ctx, fw, prev_size);
307 break;
308 }
309
310 if (curr_code < face->num_glyphs)
311 {
312 state = new_state;
313 first_code = new_first_code;
314 publish = 0;
315 }
316 }
317
318 prev_size = curr_size;
319 prev_code = curr_code;
320 }
321
322 if (font->width_table != NULL)
323 pdf_dict_put_int(ctx, fobj, PDF_NAME(DW), font->width_default);
324 if (pdf_array_len(ctx, fw) > 0)
325 pdf_dict_put(ctx, fobj, PDF_NAME(W), fw);
326 }
327 fz_always(ctx)
328 pdf_drop_obj(ctx, fw);
329 fz_catch(ctx)
330 fz_rethrow(ctx);
331}
332
333/* Descendant font construction used for CID font creation from ttf or Adobe type1 */
334static pdf_obj*
335pdf_add_descendant_cid_font(fz_context *ctx, pdf_document *doc, fz_font *font)
336{
337 FT_Face face = font->ft_face;
338 pdf_obj *fobj, *fref;
339 const char *ps_name;
340
341 fobj = pdf_new_dict(ctx, doc, 3);
342 fz_try(ctx)
343 {
344 pdf_dict_put(ctx, fobj, PDF_NAME(Type), PDF_NAME(Font));
345 if (is_truetype(face))
346 pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(CIDFontType2));
347 else
348 pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(CIDFontType0));
349
350 pdf_add_cid_system_info(ctx, doc, fobj, "Adobe", "Identity", 0);
351
352 ps_name = FT_Get_Postscript_Name(face);
353 if (ps_name)
354 pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), ps_name);
355 else
356 pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), font->name);
357
358 pdf_add_font_descriptor(ctx, doc, fobj, font);
359
360 /* We may have a cid font already with width info in source font and no cmap in the ft face */
361 pdf_add_cid_font_widths(ctx, doc, fobj, font);
362
363 fref = pdf_add_object(ctx, doc, fobj);
364 }
365 fz_always(ctx)
366 pdf_drop_obj(ctx, fobj);
367 fz_catch(ctx)
368 fz_rethrow(ctx);
369 return fref;
370}
371
372static int next_range(int *table, int size, int k)
373{
374 int n;
375 for (n = 1; k + n < size; ++n)
376 {
377 if ((k & 0xFF00) != ((k+n) & 0xFF00)) /* high byte changes */
378 break;
379 if (table[k] + n != table[k+n])
380 break;
381 }
382 return n;
383}
384
385/* Create the ToUnicode CMap. */
386static void
387pdf_add_to_unicode(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, fz_font *font)
388{
389 FT_Face face = font->ft_face;
390 fz_buffer *buf;
391
392 int *table;
393 int num_seq = 0;
394 int num_chr = 0;
395 int n, k;
396
397 /* Populate reverse cmap table */
398 {
399 FT_ULong ucs;
400 FT_UInt gid;
401
402 table = fz_calloc(ctx, face->num_glyphs, sizeof *table);
403 fz_lock(ctx, FZ_LOCK_FREETYPE);
404 ucs = FT_Get_First_Char(face, &gid);
405 while (gid > 0)
406 {
407 if (gid < (FT_ULong)face->num_glyphs && face->num_glyphs > 0)
408 table[gid] = ucs;
409 ucs = FT_Get_Next_Char(face, ucs, &gid);
410 }
411 fz_unlock(ctx, FZ_LOCK_FREETYPE);
412 }
413
414 for (k = 0; k < face->num_glyphs; k += n)
415 {
416 n = next_range(table, face->num_glyphs, k);
417 if (n > 1)
418 ++num_seq;
419 else if (table[k] > 0)
420 ++num_chr;
421 }
422
423 /* No mappings available... */
424 if (num_seq + num_chr == 0)
425 {
426 fz_warn(ctx, "cannot create ToUnicode mapping for %s", font->name);
427 fz_free(ctx, table);
428 return;
429 }
430
431 buf = fz_new_buffer(ctx, 0);
432 fz_try(ctx)
433 {
434 /* Header boiler plate */
435 fz_append_string(ctx, buf, "/CIDInit /ProcSet findresource begin\n");
436 fz_append_string(ctx, buf, "12 dict begin\n");
437 fz_append_string(ctx, buf, "begincmap\n");
438 fz_append_string(ctx, buf, "/CIDSystemInfo <</Registry(Adobe)/Ordering(UCS)/Supplement 0>> def\n");
439 fz_append_string(ctx, buf, "/CMapName /Adobe-Identity-UCS def\n");
440 fz_append_string(ctx, buf, "/CMapType 2 def\n");
441 fz_append_string(ctx, buf, "1 begincodespacerange\n");
442 fz_append_string(ctx, buf, "<0000> <FFFF>\n");
443 fz_append_string(ctx, buf, "endcodespacerange\n");
444
445 /* Note to have a valid CMap, the number of entries in table set can
446 * not exceed 100, so we have to break into multiple tables. Also, note
447 * that to reduce the file size we should be looking for sequential
448 * ranges. Per Adobe technical note #5411, we can't have a range
449 * cross a boundary where the high order byte changes */
450
451 /* First the ranges */
452 if (num_seq > 0)
453 {
454 int count = 0;
455 if (num_seq > 100)
456 {
457 fz_append_string(ctx, buf, "100 beginbfrange\n");
458 num_seq -= 100;
459 }
460 else
461 fz_append_printf(ctx, buf, "%d beginbfrange\n", num_seq);
462 for (k = 0; k < face->num_glyphs; k += n)
463 {
464 n = next_range(table, face->num_glyphs, k);
465 if (n > 1)
466 {
467 if (count == 100)
468 {
469 fz_append_string(ctx, buf, "endbfrange\n");
470 if (num_seq > 100)
471 {
472 fz_append_string(ctx, buf, "100 beginbfrange\n");
473 num_seq -= 100;
474 }
475 else
476 fz_append_printf(ctx, buf, "%d beginbfrange\n", num_seq);
477 count = 0;
478 }
479 fz_append_printf(ctx, buf, "<%04x> <%04x> <%04x>\n", k, k+n-1, table[k]);
480 ++count;
481 }
482 }
483 fz_append_string(ctx, buf, "endbfrange\n");
484 }
485
486 /* Then the singles */
487 if (num_chr > 0)
488 {
489 int count = 0;
490 if (num_chr > 100)
491 {
492 fz_append_string(ctx, buf, "100 beginbfchar\n");
493 num_chr -= 100;
494 }
495 else
496 fz_append_printf(ctx, buf, "%d beginbfchar\n", num_chr);
497 for (k = 0; k < face->num_glyphs; k += n)
498 {
499 n = next_range(table, face->num_glyphs, k);
500 if (n == 1 && table[k] > 0)
501 {
502 if (count == 100)
503 {
504 fz_append_string(ctx, buf, "endbfchar\n");
505 if (num_chr > 100)
506 {
507 fz_append_string(ctx, buf, "100 beginbfchar\n");
508 num_chr -= 100;
509 }
510 else
511 fz_append_printf(ctx, buf, "%d beginbfchar\n", num_chr);
512 count = 0;
513 }
514 fz_append_printf(ctx, buf, "<%04x> <%04x>\n", k, table[k]);
515 ++count;
516 }
517 }
518 fz_append_string(ctx, buf, "endbfchar\n");
519 }
520
521 /* Trailer boiler plate */
522 fz_append_string(ctx, buf, "endcmap\n");
523 fz_append_string(ctx, buf, "CMapName currentdict /CMap defineresource pop\n");
524 fz_append_string(ctx, buf, "end\nend\n");
525
526 pdf_dict_put_drop(ctx, fobj, PDF_NAME(ToUnicode), pdf_add_stream(ctx, doc, buf, NULL, 0));
527 }
528 fz_always(ctx)
529 {
530 fz_free(ctx, table);
531 fz_drop_buffer(ctx, buf);
532 }
533 fz_catch(ctx)
534 fz_rethrow(ctx);
535}
536
537/* Creates CID font with Identity-H CMap and a ToUnicode CMap that is created by
538 * using the TTF cmap table "backwards" to go from the GID to a Unicode value.
539 * We can possibly get width information that may have been embedded in
540 * the PDF /W array (or W2 if vertical text) */
541pdf_obj *
542pdf_add_cid_font(fz_context *ctx, pdf_document *doc, fz_font *font)
543{
544 pdf_obj *fobj = NULL;
545 pdf_obj *fref = NULL;
546 pdf_obj *dfonts = NULL;
547 unsigned char digest[16];
548
549 fref = pdf_find_font_resource(ctx, doc, PDF_CID_FONT_RESOURCE, 0, font, digest);
550 if (fref)
551 return fref;
552
553 fobj = pdf_add_new_dict(ctx, doc, 10);
554 fz_try(ctx)
555 {
556 pdf_dict_put(ctx, fobj, PDF_NAME(Type), PDF_NAME(Font));
557 pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(Type0));
558 pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), font->name);
559 pdf_dict_put(ctx, fobj, PDF_NAME(Encoding), PDF_NAME(Identity_H));
560 pdf_add_to_unicode(ctx, doc, fobj, font);
561
562 dfonts = pdf_dict_put_array(ctx, fobj, PDF_NAME(DescendantFonts), 1);
563 pdf_array_push_drop(ctx, dfonts, pdf_add_descendant_cid_font(ctx, doc, font));
564
565 fref = pdf_insert_font_resource(ctx, doc, digest, fobj);
566 }
567 fz_always(ctx)
568 pdf_drop_obj(ctx, fobj);
569 fz_catch(ctx)
570 fz_rethrow(ctx);
571 return fref;
572}
573
574/* Create simple (8-bit encoding) fonts */
575
576static void
577pdf_add_simple_font_encoding_imp(fz_context *ctx, pdf_document *doc, pdf_obj *font, const char *glyph_names[])
578{
579 pdf_obj *enc, *diff;
580 int i, last;
581
582 enc = pdf_dict_put_dict(ctx, font, PDF_NAME(Encoding), 2);
583 pdf_dict_put(ctx, enc, PDF_NAME(BaseEncoding), PDF_NAME(WinAnsiEncoding));
584 diff = pdf_dict_put_array(ctx, enc, PDF_NAME(Differences), 129);
585 last = 0;
586 for (i = 128; i < 256; ++i)
587 {
588 const char *glyph = glyph_names[i];
589 if (glyph)
590 {
591 if (last != i-1)
592 pdf_array_push_int(ctx, diff, i);
593 last = i;
594 pdf_array_push_name(ctx, diff, glyph);
595 }
596 }
597}
598
599static void
600pdf_add_simple_font_encoding(fz_context *ctx, pdf_document *doc, pdf_obj *fobj, int encoding)
601{
602 switch (encoding)
603 {
604 default:
605 case PDF_SIMPLE_ENCODING_LATIN:
606 pdf_dict_put(ctx, fobj, PDF_NAME(Encoding), PDF_NAME(WinAnsiEncoding));
607 break;
608 case PDF_SIMPLE_ENCODING_GREEK:
609 pdf_add_simple_font_encoding_imp(ctx, doc, fobj, fz_glyph_name_from_iso8859_7);
610 break;
611 case PDF_SIMPLE_ENCODING_CYRILLIC:
612 pdf_add_simple_font_encoding_imp(ctx, doc, fobj, fz_glyph_name_from_koi8u);
613 break;
614 }
615}
616
617pdf_obj *
618pdf_add_simple_font(fz_context *ctx, pdf_document *doc, fz_font *font, int encoding)
619{
620 FT_Face face = font->ft_face;
621 pdf_obj *fobj = NULL;
622 pdf_obj *fref = NULL;
623 const char **enc;
624 unsigned char digest[16];
625
626 fref = pdf_find_font_resource(ctx, doc, PDF_SIMPLE_FONT_RESOURCE, encoding, font, digest);
627 if (fref)
628 return fref;
629
630 switch (encoding)
631 {
632 default:
633 case PDF_SIMPLE_ENCODING_LATIN: enc = fz_glyph_name_from_windows_1252; break;
634 case PDF_SIMPLE_ENCODING_GREEK: enc = fz_glyph_name_from_iso8859_7; break;
635 case PDF_SIMPLE_ENCODING_CYRILLIC: enc = fz_glyph_name_from_koi8u; break;
636 }
637
638 fobj = pdf_add_new_dict(ctx, doc, 10);
639 fz_try(ctx)
640 {
641 pdf_dict_put(ctx, fobj, PDF_NAME(Type), PDF_NAME(Font));
642 if (is_truetype(face))
643 pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(TrueType));
644 else
645 pdf_dict_put(ctx, fobj, PDF_NAME(Subtype), PDF_NAME(Type1));
646
647 if (!is_builtin_font(ctx, font))
648 {
649 const char *ps_name = FT_Get_Postscript_Name(face);
650 if (!ps_name)
651 ps_name = font->name;
652 pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), ps_name);
653 pdf_add_simple_font_encoding(ctx, doc, fobj, encoding);
654 pdf_add_simple_font_widths(ctx, doc, fobj, font, enc);
655 pdf_add_font_descriptor(ctx, doc, fobj, font);
656 }
657 else
658 {
659 pdf_dict_put_name(ctx, fobj, PDF_NAME(BaseFont), pdf_clean_font_name(font->name));
660 pdf_add_simple_font_encoding(ctx, doc, fobj, encoding);
661 if (encoding != PDF_SIMPLE_ENCODING_LATIN)
662 pdf_add_simple_font_widths(ctx, doc, fobj, font, enc);
663 }
664
665 fref = pdf_insert_font_resource(ctx, doc, digest, fobj);
666 }
667 fz_always(ctx)
668 {
669 pdf_drop_obj(ctx, fobj);
670 }
671 fz_catch(ctx)
672 fz_rethrow(ctx);
673 return fref;
674}
675
676int
677pdf_font_writing_supported(fz_font *font)
678{
679 if (font->ft_face == NULL || font->buffer == NULL || font->buffer->len < 4)
680 return 0;
681 if (is_ttc(font))
682 return 0;
683 if (is_truetype(font->ft_face))
684 return 1;
685 if (is_postscript(font->ft_face))
686 return 1;
687 return 0;
688}
689
690/* Add a non-embedded UTF16-encoded CID-font for the CJK scripts: CNS1, GB1, Japan1, or Korea1 */
691pdf_obj *
692pdf_add_cjk_font(fz_context *ctx, pdf_document *doc, fz_font *fzfont, int script, int wmode, int serif)
693{
694 pdf_obj *fref, *font, *subfont, *fontdesc;
695 pdf_obj *dfonts;
696 fz_rect bbox = { -200, -200, 1200, 1200 };
697 unsigned char digest[16];
698 int flags;
699
700 const char *basefont, *encoding, *ordering;
701 int supplement;
702
703 switch (script)
704 {
705 default:
706 script = FZ_ADOBE_CNS;
707 /* fall through */
708 case FZ_ADOBE_CNS: /* traditional chinese */
709 basefont = serif ? "Ming" : "Fangti";
710 encoding = wmode ? "UniCNS-UTF16-V" : "UniCNS-UTF16-H";
711 ordering = "CNS1";
712 supplement = 7;
713 break;
714 case FZ_ADOBE_GB: /* simplified chinese */
715 basefont = serif ? "Song" : "Heiti";
716 encoding = wmode ? "UniGB-UTF16-V" : "UniGB-UTF16-H";
717 ordering = "GB1";
718 supplement = 5;
719 break;
720 case FZ_ADOBE_JAPAN:
721 basefont = serif ? "Mincho" : "Gothic";
722 encoding = wmode ? "UniJIS-UTF16-V" : "UniJIS-UTF16-H";
723 ordering = "Japan1";
724 supplement = 6;
725 break;
726 case FZ_ADOBE_KOREA:
727 basefont = serif ? "Batang" : "Dotum";
728 encoding = wmode ? "UniKS-UTF16-V" : "UniKS-UTF16-H";
729 ordering = "Korea1";
730 supplement = 2;
731 break;
732 }
733
734 flags = PDF_FD_SYMBOLIC;
735 if (serif)
736 flags |= PDF_FD_SERIF;
737
738 fref = pdf_find_font_resource(ctx, doc, PDF_CJK_FONT_RESOURCE, script, fzfont, digest);
739 if (fref)
740 return fref;
741
742 font = pdf_add_new_dict(ctx, doc, 5);
743 fz_try(ctx)
744 {
745 pdf_dict_put(ctx, font, PDF_NAME(Type), PDF_NAME(Font));
746 pdf_dict_put(ctx, font, PDF_NAME(Subtype), PDF_NAME(Type0));
747 pdf_dict_put_name(ctx, font, PDF_NAME(BaseFont), basefont);
748 pdf_dict_put_name(ctx, font, PDF_NAME(Encoding), encoding);
749 dfonts = pdf_dict_put_array(ctx, font, PDF_NAME(DescendantFonts), 1);
750 pdf_array_push_drop(ctx, dfonts, subfont = pdf_add_new_dict(ctx, doc, 5));
751 {
752 pdf_dict_put(ctx, subfont, PDF_NAME(Type), PDF_NAME(Font));
753 pdf_dict_put(ctx, subfont, PDF_NAME(Subtype), PDF_NAME(CIDFontType0));
754 pdf_dict_put_name(ctx, subfont, PDF_NAME(BaseFont), basefont);
755 pdf_add_cid_system_info(ctx, doc, subfont, "Adobe", ordering, supplement);
756 fontdesc = pdf_add_new_dict(ctx, doc, 8);
757 pdf_dict_put_drop(ctx, subfont, PDF_NAME(FontDescriptor), fontdesc);
758 {
759 pdf_dict_put(ctx, fontdesc, PDF_NAME(Type), PDF_NAME(FontDescriptor));
760 pdf_dict_put_text_string(ctx, fontdesc, PDF_NAME(FontName), basefont);
761 pdf_dict_put_rect(ctx, fontdesc, PDF_NAME(FontBBox), bbox);
762 pdf_dict_put_int(ctx, fontdesc, PDF_NAME(Flags), flags);
763 pdf_dict_put_int(ctx, fontdesc, PDF_NAME(ItalicAngle), 0);
764 pdf_dict_put_int(ctx, fontdesc, PDF_NAME(Ascent), 1000);
765 pdf_dict_put_int(ctx, fontdesc, PDF_NAME(Descent), -200);
766 pdf_dict_put_int(ctx, fontdesc, PDF_NAME(StemV), 80);
767 }
768 }
769
770 fref = pdf_insert_font_resource(ctx, doc, digest, font);
771 }
772 fz_always(ctx)
773 pdf_drop_obj(ctx, font);
774 fz_catch(ctx)
775 fz_rethrow(ctx);
776
777 return fref;
778}
779