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