comparison mupdf-source/source/pdf/pdf-font-add.c @ 2:b50eed0cc0ef upstream

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