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