/src/ghostpdl/pdf/pdf_font3.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2019-2025 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | /* code for type 3 font handling */ |
17 | | |
18 | | #include "pdf_int.h" |
19 | | #include "pdf_stack.h" |
20 | | #include "pdf_array.h" |
21 | | #include "pdf_dict.h" |
22 | | #include "pdf_font_types.h" |
23 | | #include "pdf_gstate.h" |
24 | | #include "pdf_font.h" |
25 | | #include "pdf_font3.h" |
26 | | #include "pdf_deref.h" |
27 | | #include "gscencs.h" |
28 | | #include "gscedata.h" /* For the encoding arrays */ |
29 | | #include "gsccode.h" /* For the Encoding indices */ |
30 | | #include "gsuid.h" /* For no_UniqueID */ |
31 | | #include "gsutil.h" /* For gs_next_ids() */ |
32 | | |
33 | | static int |
34 | | pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont, |
35 | | gs_char chr, gs_glyph glyph) |
36 | 2.67k | { |
37 | 2.67k | int code = 0; |
38 | 2.67k | pdf_font_type3 *font; |
39 | 2.67k | pdf_name *GlyphName = NULL; |
40 | 2.67k | pdf_stream *CharProc = NULL; |
41 | 2.67k | int SavedTextBlockDepth = 0; |
42 | 2.67k | char Notdef[8] = {".notdef"}; |
43 | | |
44 | 2.67k | font = (pdf_font_type3 *)pfont->client_data; |
45 | | |
46 | 2.67k | SavedTextBlockDepth = OBJ_CTX(font)->text.BlockDepth; |
47 | 2.67k | code = pdfi_array_get(OBJ_CTX(font), font->Encoding, (uint64_t)chr, (pdf_obj **)&GlyphName); |
48 | 2.67k | if (code < 0) |
49 | 0 | return code; |
50 | | |
51 | 2.67k | code = pdfi_dict_get_by_key(OBJ_CTX(font), font->CharProcs, GlyphName, (pdf_obj **)&CharProc); |
52 | 2.67k | if (code == gs_error_undefined) { |
53 | 581 | byte *Key = NULL; |
54 | | /* Can't find the named glyph, try to find a /.notdef as a substitute */ |
55 | 581 | Key = gs_alloc_bytes(OBJ_MEMORY(font), 8, "working buffer for BuildChar"); |
56 | 581 | if (Key == NULL) |
57 | 0 | goto build_char_error; |
58 | 581 | memset(Key, 0x00, 8); |
59 | 581 | memcpy(Key, Notdef, 8); |
60 | 581 | code = pdfi_dict_get(OBJ_CTX(font), font->CharProcs, (const char *)Key, (pdf_obj **)&CharProc); |
61 | 581 | gs_free_object(OBJ_MEMORY(font), Key, "working buffer for BuildChar"); |
62 | 581 | if (code == gs_error_undefined) { |
63 | 578 | code = 0; |
64 | 578 | goto build_char_error; |
65 | 578 | } |
66 | 581 | } |
67 | 2.10k | if (code < 0) |
68 | 73 | goto build_char_error; |
69 | 2.02k | if (pdfi_type_of(CharProc) != PDF_STREAM) { |
70 | 9 | code = gs_note_error(gs_error_typecheck); |
71 | 9 | goto build_char_error; |
72 | 9 | } |
73 | | |
74 | 2.01k | OBJ_CTX(font)->text.BlockDepth = 0; |
75 | 2.01k | OBJ_CTX(font)->text.inside_CharProc = true; |
76 | 2.01k | OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none; |
77 | | |
78 | | /* We used to have code here to emulate some Acrobat behaviour, but it interferes with getting |
79 | | * the result of /tests/pdf/safedocs/ContentStreamNoCycleType3insideType3.pdf because for that |
80 | | * file the nested type 3 font CharProc must inherit the stroke colour from the outer type 3 |
81 | | * font CharProc graphics state at the time the glyph is drawn. So the code was removed. The |
82 | | * Acrobat behaviour is not mentioned in the spec and Acrobat is completely incapable of |
83 | | * getting Patterns right, per the spec, when they are 'inside' multiple levels of content |
84 | | * streams. |
85 | | * The old comment began : |
86 | | * |
87 | | * * It turns out that if a type 3 font uses a stroke to draw, and does not |
88 | | * * acrually set the stroke colour, then we must use the fill colour instead. |
89 | | * * In effect we start a type 3 BuildChar with stroke colour = fill colour. |
90 | | */ |
91 | 2.01k | code = pdfi_gsave(OBJ_CTX(font)); |
92 | 2.01k | if (code >= 0) { |
93 | 2.01k | code = pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc"); |
94 | 2.01k | (void)pdfi_grestore(OBJ_CTX(font)); |
95 | 2.01k | } |
96 | | |
97 | 2.01k | OBJ_CTX(font)->text.inside_CharProc = false; |
98 | 2.01k | OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none; |
99 | 2.01k | OBJ_CTX(font)->text.BlockDepth = SavedTextBlockDepth; |
100 | | |
101 | 2.67k | build_char_error: |
102 | 2.67k | pdfi_countdown(GlyphName); |
103 | 2.67k | pdfi_countdown(CharProc); |
104 | 2.67k | return code; |
105 | 2.01k | } |
106 | | |
107 | | static int alloc_type3_font(pdf_context *ctx, pdf_font_type3 **font) |
108 | 167 | { |
109 | 167 | pdf_font_type3 *t3font = NULL; |
110 | | |
111 | 167 | t3font = (pdf_font_type3 *)gs_alloc_bytes(ctx->memory, sizeof(pdf_font_type3), "pdfi_alloc_type3_font"); |
112 | 167 | if (t3font == NULL) |
113 | 0 | return_error(gs_error_VMerror); |
114 | | |
115 | 167 | memset(t3font, 0x00, sizeof(pdf_font_type3)); |
116 | 167 | (t3font)->ctx = ctx; |
117 | 167 | (t3font)->type = PDF_FONT; |
118 | | |
119 | | #if REFCNT_DEBUG |
120 | | (t3font)->UID = ctx->UID++; |
121 | | outprintf(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", t3font->type, t3font->UID); |
122 | | #endif |
123 | | |
124 | | |
125 | 167 | pdfi_countup(t3font); |
126 | | |
127 | 167 | t3font->pfont = gs_alloc_struct(ctx->memory, gs_font_base, &st_gs_font_base, |
128 | 167 | "pdfi (type 3 font)"); |
129 | 167 | if (t3font->pfont == NULL) { |
130 | 0 | pdfi_countdown(t3font); |
131 | 0 | return_error(gs_error_VMerror); |
132 | 0 | } |
133 | | |
134 | 167 | memset(t3font->pfont, 0x00, sizeof(gs_font_base)); |
135 | 167 | t3font->ctx = ctx; |
136 | 167 | t3font->pdfi_font_type = e_pdf_font_type3; |
137 | | |
138 | 167 | gs_make_identity(&t3font->pfont->orig_FontMatrix); |
139 | 167 | gs_make_identity(&t3font->pfont->FontMatrix); |
140 | 167 | t3font->pfont->next = t3font->pfont->prev = 0; |
141 | 167 | t3font->pfont->memory = ctx->memory; |
142 | 167 | t3font->pfont->dir = ctx->font_dir; |
143 | 167 | t3font->pfont->is_resource = false; |
144 | 167 | gs_notify_init(&t3font->pfont->notify_list, ctx->memory); |
145 | 167 | t3font->pfont->base = (gs_font *) t3font->pfont; |
146 | 167 | t3font->pfont->client_data = t3font; |
147 | 167 | t3font->pfont->WMode = 0; |
148 | 167 | t3font->pfont->PaintType = 0; |
149 | 167 | t3font->pfont->StrokeWidth = 0; |
150 | 167 | t3font->pfont->is_cached = 0; |
151 | 167 | t3font->pfont->procs.init_fstack = gs_default_init_fstack; |
152 | 167 | t3font->pfont->procs.next_char_glyph = gs_default_next_char_glyph; |
153 | 167 | t3font->pfont->FAPI = NULL; |
154 | 167 | t3font->pfont->FAPI_font_data = NULL; |
155 | 167 | t3font->pfont->procs.glyph_name = ctx->get_glyph_name; |
156 | 167 | t3font->pfont->procs.decode_glyph = pdfi_decode_glyph; |
157 | 167 | t3font->pfont->procs.define_font = gs_no_define_font; |
158 | 167 | t3font->pfont->procs.make_font = gs_no_make_font; |
159 | | |
160 | 167 | t3font->default_font_info = gs_default_font_info; |
161 | 167 | t3font->pfont->procs.font_info = pdfi_default_font_info; |
162 | | |
163 | 167 | t3font->pfont->procs.glyph_info = gs_default_glyph_info; |
164 | 167 | t3font->pfont->procs.glyph_outline = gs_no_glyph_outline; |
165 | 167 | t3font->pfont->procs.encode_char = pdfi_encode_char; |
166 | 167 | t3font->pfont->procs.build_char = pdfi_type3_build_char; |
167 | 167 | t3font->pfont->procs.same_font = gs_default_same_font; |
168 | 167 | t3font->pfont->procs.enumerate_glyph = gs_no_enumerate_glyph; |
169 | | |
170 | 167 | t3font->pfont->FontType = ft_PDF_user_defined; |
171 | | /* outlines ? Bitmaps ? */ |
172 | 167 | t3font->pfont->ExactSize = fbit_use_bitmaps; |
173 | 167 | t3font->pfont->InBetweenSize = fbit_use_bitmaps; |
174 | 167 | t3font->pfont->TransformedChar = fbit_transform_bitmaps; |
175 | | |
176 | 167 | t3font->pfont->encoding_index = ENCODING_INDEX_UNKNOWN; |
177 | 167 | t3font->pfont->nearest_encoding_index = ENCODING_INDEX_UNKNOWN; |
178 | | |
179 | 167 | t3font->pfont->client_data = (void *)t3font; |
180 | 167 | t3font->pfont->id = gs_next_ids(ctx->memory, 1); |
181 | 167 | uid_set_UniqueID(&t3font->pfont->UID, no_UniqueID); |
182 | | |
183 | 167 | *font = (pdf_font_type3 *)t3font; |
184 | 167 | return 0; |
185 | 167 | } |
186 | | |
187 | | int pdfi_free_font_type3(pdf_obj *font) |
188 | 167 | { |
189 | 167 | pdf_font_type3 *t3font = (pdf_font_type3 *)font; |
190 | | |
191 | 167 | if (t3font->pfont) |
192 | 167 | gs_free_object(OBJ_MEMORY(t3font), t3font->pfont, "Free type 3 font"); |
193 | | |
194 | 167 | if (t3font->Widths) |
195 | 141 | gs_free_object(OBJ_MEMORY(t3font), t3font->Widths, "Free type 3 font Widths array"); |
196 | | |
197 | 167 | pdfi_countdown(t3font->PDF_font); |
198 | 167 | pdfi_countdown(t3font->FontDescriptor); |
199 | 167 | pdfi_countdown(t3font->CharProcs); |
200 | 167 | pdfi_countdown(t3font->Encoding); |
201 | 167 | pdfi_countdown(t3font->ToUnicode); |
202 | 167 | pdfi_countdown(t3font->filename); /* Should never exist, but just in case */ |
203 | 167 | pdfi_countdown(t3font->copyright); |
204 | 167 | pdfi_countdown(t3font->notice); |
205 | 167 | pdfi_countdown(t3font->fullname); |
206 | 167 | pdfi_countdown(t3font->familyname); |
207 | | |
208 | 167 | gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font"); |
209 | 167 | return 0; |
210 | 167 | } |
211 | | |
212 | | |
213 | | int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont) |
214 | 167 | { |
215 | 167 | int code = 0; |
216 | 167 | pdf_font_type3 *font = NULL; |
217 | 167 | pdf_obj *obj = NULL; |
218 | 167 | pdf_obj *tounicode = NULL; |
219 | | |
220 | 167 | *ppdffont = NULL; |
221 | 167 | code = alloc_type3_font(ctx, &font); |
222 | 167 | if (code < 0) |
223 | 0 | return code; |
224 | | |
225 | 167 | font->object_num = font_dict->object_num; |
226 | 167 | font->generation_num = font_dict->generation_num; |
227 | 167 | font->indirect_num = font_dict->indirect_num; |
228 | 167 | font->indirect_gen = font_dict->indirect_gen; |
229 | | |
230 | 167 | code = pdfi_dict_get_type(ctx, font_dict, "FontBBox", PDF_ARRAY, &obj); |
231 | 167 | if (code < 0) |
232 | 1 | goto font3_error; |
233 | 166 | code = pdfi_array_to_gs_rect(ctx, (pdf_array *)obj, &font->pfont->FontBBox); |
234 | 166 | if (code < 0) |
235 | 0 | goto font3_error; |
236 | 166 | pdfi_countdown(obj); |
237 | 166 | obj = NULL; |
238 | | |
239 | 166 | code = pdfi_dict_get_type(ctx, font_dict, "FontMatrix", PDF_ARRAY, &obj); |
240 | 166 | if (code < 0) |
241 | 2 | goto font3_error; |
242 | 164 | code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->orig_FontMatrix); |
243 | 164 | if (code < 0) |
244 | 1 | goto font3_error; |
245 | 163 | code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->FontMatrix); |
246 | 163 | if (code < 0) |
247 | 0 | goto font3_error; |
248 | 163 | pdfi_countdown(obj); |
249 | 163 | obj = NULL; |
250 | | |
251 | 163 | code = pdfi_dict_get(ctx, font_dict, "CharProcs", (pdf_obj **)&font->CharProcs); |
252 | 163 | if (code < 0) |
253 | 7 | goto font3_error; |
254 | | |
255 | | |
256 | 156 | code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor); |
257 | 156 | if (code < 0) |
258 | 1 | goto font3_error; |
259 | | |
260 | 155 | if (font->FontDescriptor != NULL) { |
261 | 18 | pdf_obj *Name = NULL; |
262 | | |
263 | 18 | code = pdfi_dict_get_type(ctx, (pdf_dict *) font->FontDescriptor, "FontName", PDF_NAME, (pdf_obj**)&Name); |
264 | 18 | if (code < 0) |
265 | 1 | pdfi_set_warning(ctx, 0, NULL, W_PDF_FDESC_BAD_FONTNAME, "pdfi_load_font", ""); |
266 | 18 | pdfi_countdown(Name); |
267 | 18 | } |
268 | | |
269 | 155 | pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font); |
270 | | /* ignore errors with widths... for now */ |
271 | 155 | (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, 1.0); |
272 | | |
273 | | |
274 | 155 | code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj); |
275 | 155 | if (code < 0) |
276 | 13 | goto font3_error; |
277 | | |
278 | 142 | code = pdfi_create_Encoding(ctx, (pdf_font *)font, obj, NULL, (pdf_obj **)&font->Encoding); |
279 | 142 | if (code < 0) |
280 | 0 | goto font3_error; |
281 | 142 | pdfi_countdown(obj); |
282 | | |
283 | 142 | font->PDF_font = font_dict; |
284 | 142 | pdfi_countup(font_dict); |
285 | | |
286 | 142 | if (ctx->args.ignoretounicode != true) { |
287 | 142 | code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode); |
288 | 142 | if (code >= 0 && pdfi_type_of(tounicode) == PDF_STREAM) { |
289 | 54 | pdf_cmap *tu = NULL; |
290 | 54 | code = pdfi_read_cmap(ctx, tounicode, &tu); |
291 | 54 | pdfi_countdown(tounicode); |
292 | 54 | tounicode = (pdf_obj *)tu; |
293 | 54 | } |
294 | 142 | if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) { |
295 | 89 | pdfi_countdown(tounicode); |
296 | 89 | tounicode = NULL; |
297 | 89 | code = 0; |
298 | 89 | } |
299 | 142 | } |
300 | 0 | else { |
301 | 0 | tounicode = NULL; |
302 | 0 | } |
303 | | |
304 | 142 | font->ToUnicode = tounicode; |
305 | 142 | tounicode = NULL; |
306 | | |
307 | 142 | code = replace_cache_entry(ctx, (pdf_obj *)font); |
308 | 142 | if (code < 0) |
309 | 0 | goto font3_error; |
310 | | |
311 | 142 | pdfi_font_set_orig_fonttype(ctx, (pdf_font *)font); |
312 | 142 | code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont); |
313 | 142 | if (code < 0) |
314 | 0 | goto font3_error; |
315 | | |
316 | 142 | *ppdffont = (pdf_font *)font; |
317 | | |
318 | 142 | return code; |
319 | | |
320 | 25 | font3_error: |
321 | 25 | pdfi_countdown(obj); |
322 | 25 | pdfi_countdown(font); |
323 | 25 | return code; |
324 | 142 | } |