/src/ghostpdl/pdf/pdf_font3.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Copyright (C) 2019-2022 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., 1305 Grant Avenue - Suite 200, Novato, |
13 | | CA 94945, U.S.A., +1(415)492-9861, 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 void pdfi_type3_copy_color(gs_gstate_color *src, gs_gstate_color *dest) |
34 | 22.4k | { |
35 | 22.4k | *dest->ccolor = *src->ccolor; |
36 | 22.4k | *dest->dev_color = *src->dev_color; |
37 | 22.4k | dest->color_space = src->color_space; |
38 | 22.4k | dest->effective_opm = src->effective_opm; |
39 | 22.4k | } |
40 | | |
41 | | static int |
42 | | pdfi_type3_build_char(gs_show_enum * penum, gs_gstate * pgs, gs_font * pfont, |
43 | | gs_char chr, gs_glyph glyph) |
44 | 9.06k | { |
45 | 9.06k | int code = 0; |
46 | 9.06k | pdf_font_type3 *font; |
47 | 9.06k | pdf_name *GlyphName = NULL; |
48 | 9.06k | pdf_stream *CharProc = NULL; |
49 | 9.06k | int SavedTextBlockDepth = 0; |
50 | 9.06k | char Notdef[8] = {".notdef"}; |
51 | | |
52 | 9.06k | font = (pdf_font_type3 *)pfont->client_data; |
53 | | |
54 | 9.06k | SavedTextBlockDepth = OBJ_CTX(font)->text.BlockDepth; |
55 | 9.06k | code = pdfi_array_get(OBJ_CTX(font), font->Encoding, (uint64_t)chr, (pdf_obj **)&GlyphName); |
56 | 9.06k | if (code < 0) |
57 | 0 | return code; |
58 | | |
59 | 9.06k | code = pdfi_dict_get_by_key(OBJ_CTX(font), font->CharProcs, GlyphName, (pdf_obj **)&CharProc); |
60 | 9.06k | if (code == gs_error_undefined) { |
61 | 1.40k | byte *Key = NULL; |
62 | | /* Can't find the named glyph, try to find a /.notdef as a substitute */ |
63 | 1.40k | Key = gs_alloc_bytes(OBJ_MEMORY(font), 8, "working buffer for BuildChar"); |
64 | 1.40k | if (Key == NULL) |
65 | 0 | goto build_char_error; |
66 | 1.40k | memset(Key, 0x00, 8); |
67 | 1.40k | memcpy(Key, Notdef, 8); |
68 | 1.40k | code = pdfi_dict_get(OBJ_CTX(font), font->CharProcs, (const char *)Key, (pdf_obj **)&CharProc); |
69 | 1.40k | gs_free_object(OBJ_MEMORY(font), Key, "working buffer for BuildChar"); |
70 | 1.40k | if (code == gs_error_undefined) { |
71 | 1.40k | code = 0; |
72 | 1.40k | goto build_char_error; |
73 | 1.40k | } |
74 | 1.40k | } |
75 | 7.66k | if (code < 0) |
76 | 167 | goto build_char_error; |
77 | 7.49k | if (pdfi_type_of(CharProc) != PDF_STREAM) { |
78 | 21 | code = gs_note_error(gs_error_typecheck); |
79 | 21 | goto build_char_error; |
80 | 21 | } |
81 | | |
82 | 7.47k | OBJ_CTX(font)->text.BlockDepth = 0; |
83 | 7.47k | OBJ_CTX(font)->text.inside_CharProc = true; |
84 | 7.47k | OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none; |
85 | | |
86 | 7.47k | { |
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 | | * That is annoyingly difficult to set up. We need to copy the existing |
91 | | * colour values from the structures in the gs_gstate_color structures into |
92 | | * temporary copies and copy the colour space pointer (and keep its reference |
93 | | * count correct). Then copy the fill colour values and ponter to the stroke |
94 | | * structures. Finally, after drawing the character, copy the temporary |
95 | | * saved copies back again. |
96 | | */ |
97 | 7.47k | gs_gstate_color tmp_color; |
98 | 7.47k | gs_client_color tmp_cc; |
99 | 7.47k | gx_device_color tmp_dc; |
100 | | |
101 | | /* Set up the pointers in the gs_gstate_color structure to point to |
102 | | * the temporary structures we have on the stack. |
103 | | */ |
104 | 7.47k | tmp_color.ccolor = &tmp_cc; |
105 | 7.47k | tmp_color.dev_color = &tmp_dc; |
106 | | |
107 | | /* Use the utility routine above to copy the stroke colour to the temporary copy */ |
108 | 7.47k | pdfi_type3_copy_color(&OBJ_CTX(font)->pgs->color[1], &tmp_color); |
109 | 7.47k | rc_increment_cs(tmp_color.color_space); |
110 | | /* Use the utility routine above to copy the fill colour to the stroke colour */ |
111 | 7.47k | pdfi_type3_copy_color(&OBJ_CTX(font)->pgs->color[0], &OBJ_CTX(font)->pgs->color[1]); |
112 | | |
113 | 7.47k | code = pdfi_gsave(OBJ_CTX(font)); |
114 | 7.47k | if (code >= 0) { |
115 | 7.47k | code = pdfi_run_context(OBJ_CTX(font), CharProc, font->PDF_font, true, "CharProc"); |
116 | 7.47k | (void)pdfi_grestore(OBJ_CTX(font)); |
117 | 7.47k | } |
118 | | |
119 | | /* Use the utility routine above to copy the temporary copy to the stroke colour */ |
120 | 7.47k | pdfi_type3_copy_color(&tmp_color, &OBJ_CTX(font)->pgs->color[1]); |
121 | 7.47k | rc_decrement_cs(tmp_color.color_space, "pdfi_type3_build_char"); |
122 | 7.47k | } |
123 | | |
124 | 7.47k | OBJ_CTX(font)->text.inside_CharProc = false; |
125 | 7.47k | OBJ_CTX(font)->text.CharProc_d_type = pdf_type3_d_none; |
126 | 7.47k | OBJ_CTX(font)->text.BlockDepth = SavedTextBlockDepth; |
127 | | |
128 | 9.06k | build_char_error: |
129 | 9.06k | pdfi_countdown(GlyphName); |
130 | 9.06k | pdfi_countdown(CharProc); |
131 | 9.06k | return code; |
132 | 7.47k | } |
133 | | |
134 | | static int alloc_type3_font(pdf_context *ctx, pdf_font_type3 **font) |
135 | 622 | { |
136 | 622 | pdf_font_type3 *t3font = NULL; |
137 | | |
138 | 622 | t3font = (pdf_font_type3 *)gs_alloc_bytes(ctx->memory, sizeof(pdf_font_type3), "pdfi_alloc_type3_font"); |
139 | 622 | if (t3font == NULL) |
140 | 0 | return_error(gs_error_VMerror); |
141 | | |
142 | 622 | memset(t3font, 0x00, sizeof(pdf_font_type3)); |
143 | 622 | (t3font)->ctx = ctx; |
144 | 622 | (t3font)->type = PDF_FONT; |
145 | | |
146 | | #if REFCNT_DEBUG |
147 | | (t3font)->UID = ctx->UID++; |
148 | | dmprintf2(ctx->memory, "Allocated object of type %c with UID %"PRIi64"\n", t3font->type, t3font->UID); |
149 | | #endif |
150 | | |
151 | | |
152 | 622 | pdfi_countup(t3font); |
153 | | |
154 | 622 | t3font->pfont = gs_alloc_struct(ctx->memory, gs_font_base, &st_gs_font_base, |
155 | 622 | "pdfi (type 3 font)"); |
156 | 622 | if (t3font->pfont == NULL) { |
157 | 0 | pdfi_countdown(t3font); |
158 | 0 | return_error(gs_error_VMerror); |
159 | 0 | } |
160 | | |
161 | 622 | memset(t3font->pfont, 0x00, sizeof(gs_font_base)); |
162 | 622 | t3font->ctx = ctx; |
163 | 622 | t3font->pdfi_font_type = e_pdf_font_type3; |
164 | | |
165 | 622 | gs_make_identity(&t3font->pfont->orig_FontMatrix); |
166 | 622 | gs_make_identity(&t3font->pfont->FontMatrix); |
167 | 622 | t3font->pfont->next = t3font->pfont->prev = 0; |
168 | 622 | t3font->pfont->memory = ctx->memory; |
169 | 622 | t3font->pfont->dir = ctx->font_dir; |
170 | 622 | t3font->pfont->is_resource = false; |
171 | 622 | gs_notify_init(&t3font->pfont->notify_list, ctx->memory); |
172 | 622 | t3font->pfont->base = (gs_font *) t3font->pfont; |
173 | 622 | t3font->pfont->client_data = t3font; |
174 | 622 | t3font->pfont->WMode = 0; |
175 | 622 | t3font->pfont->PaintType = 0; |
176 | 622 | t3font->pfont->StrokeWidth = 0; |
177 | 622 | t3font->pfont->is_cached = 0; |
178 | 622 | t3font->pfont->procs.init_fstack = gs_default_init_fstack; |
179 | 622 | t3font->pfont->procs.next_char_glyph = gs_default_next_char_glyph; |
180 | 622 | t3font->pfont->FAPI = NULL; |
181 | 622 | t3font->pfont->FAPI_font_data = NULL; |
182 | 622 | t3font->pfont->procs.glyph_name = ctx->get_glyph_name; |
183 | 622 | t3font->pfont->procs.decode_glyph = pdfi_decode_glyph; |
184 | 622 | t3font->pfont->procs.define_font = gs_no_define_font; |
185 | 622 | t3font->pfont->procs.make_font = gs_no_make_font; |
186 | 622 | t3font->pfont->procs.font_info = gs_default_font_info; |
187 | 622 | t3font->pfont->procs.glyph_info = gs_default_glyph_info; |
188 | 622 | t3font->pfont->procs.glyph_outline = gs_no_glyph_outline; |
189 | 622 | t3font->pfont->procs.encode_char = pdfi_encode_char; |
190 | 622 | t3font->pfont->procs.build_char = pdfi_type3_build_char; |
191 | 622 | t3font->pfont->procs.same_font = gs_default_same_font; |
192 | 622 | t3font->pfont->procs.enumerate_glyph = gs_no_enumerate_glyph; |
193 | | |
194 | 622 | t3font->pfont->FontType = ft_PDF_user_defined; |
195 | | /* outlines ? Bitmaps ? */ |
196 | 622 | t3font->pfont->ExactSize = fbit_use_bitmaps; |
197 | 622 | t3font->pfont->InBetweenSize = fbit_use_bitmaps; |
198 | 622 | t3font->pfont->TransformedChar = fbit_transform_bitmaps; |
199 | | |
200 | 622 | t3font->pfont->encoding_index = 1; /****** WRONG ******/ |
201 | 622 | t3font->pfont->nearest_encoding_index = 1; /****** WRONG ******/ |
202 | | |
203 | 622 | t3font->pfont->client_data = (void *)t3font; |
204 | 622 | t3font->pfont->id = gs_next_ids(ctx->memory, 1); |
205 | 622 | uid_set_UniqueID(&t3font->pfont->UID, no_UniqueID); |
206 | | |
207 | 622 | *font = (pdf_font_type3 *)t3font; |
208 | 622 | return 0; |
209 | 622 | } |
210 | | |
211 | | int pdfi_free_font_type3(pdf_obj *font) |
212 | 622 | { |
213 | 622 | pdf_font_type3 *t3font = (pdf_font_type3 *)font; |
214 | | |
215 | 622 | if (t3font->pfont) |
216 | 622 | gs_free_object(OBJ_MEMORY(t3font), t3font->pfont, "Free type 3 font"); |
217 | | |
218 | 622 | if (t3font->Widths) |
219 | 578 | gs_free_object(OBJ_MEMORY(t3font), t3font->Widths, "Free type 3 font Widths array"); |
220 | | |
221 | 622 | pdfi_countdown(t3font->PDF_font); |
222 | 622 | pdfi_countdown(t3font->FontDescriptor); |
223 | 622 | pdfi_countdown(t3font->CharProcs); |
224 | 622 | pdfi_countdown(t3font->Encoding); |
225 | 622 | pdfi_countdown(t3font->ToUnicode); |
226 | 622 | pdfi_countdown(t3font->filename); /* Should never exist, but just in case */ |
227 | | |
228 | 622 | gs_free_object(OBJ_MEMORY(font), font, "Free type 3 font"); |
229 | 622 | return 0; |
230 | 622 | } |
231 | | |
232 | | |
233 | | int pdfi_read_type3_font(pdf_context *ctx, pdf_dict *font_dict, pdf_dict *stream_dict, pdf_dict *page_dict, pdf_font **ppdffont) |
234 | 622 | { |
235 | 622 | int code = 0; |
236 | 622 | pdf_font_type3 *font = NULL; |
237 | 622 | pdf_obj *obj = NULL; |
238 | 622 | pdf_obj *tounicode = NULL; |
239 | | |
240 | 622 | *ppdffont = NULL; |
241 | 622 | code = alloc_type3_font(ctx, &font); |
242 | 622 | if (code < 0) |
243 | 0 | return code; |
244 | | |
245 | 622 | font->object_num = font_dict->object_num; |
246 | 622 | font->generation_num = font_dict->generation_num; |
247 | 622 | font->indirect_num = font_dict->indirect_num; |
248 | 622 | font->indirect_gen = font_dict->indirect_gen; |
249 | | |
250 | 622 | code = pdfi_dict_get_type(ctx, font_dict, "FontBBox", PDF_ARRAY, &obj); |
251 | 622 | if (code < 0) |
252 | 2 | goto font3_error; |
253 | 620 | code = pdfi_array_to_gs_rect(ctx, (pdf_array *)obj, &font->pfont->FontBBox); |
254 | 620 | if (code < 0) |
255 | 2 | goto font3_error; |
256 | 618 | pdfi_countdown(obj); |
257 | 618 | obj = NULL; |
258 | | |
259 | 618 | code = pdfi_dict_get_type(ctx, font_dict, "FontMatrix", PDF_ARRAY, &obj); |
260 | 618 | if (code < 0) |
261 | 0 | goto font3_error; |
262 | 618 | code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->orig_FontMatrix); |
263 | 618 | if (code < 0) |
264 | 4 | goto font3_error; |
265 | 614 | code = pdfi_array_to_gs_matrix(ctx, (pdf_array *)obj, &font->pfont->FontMatrix); |
266 | 614 | if (code < 0) |
267 | 0 | goto font3_error; |
268 | 614 | pdfi_countdown(obj); |
269 | 614 | obj = NULL; |
270 | | |
271 | 614 | code = pdfi_dict_get(ctx, font_dict, "CharProcs", (pdf_obj **)&font->CharProcs); |
272 | 614 | if (code < 0) |
273 | 17 | goto font3_error; |
274 | | |
275 | | |
276 | 597 | code = pdfi_dict_knownget_type(ctx, font_dict, "FontDescriptor", PDF_DICT, (pdf_obj **)&font->FontDescriptor); |
277 | 597 | if (code < 0) |
278 | 6 | goto font3_error; |
279 | | |
280 | 591 | pdfi_font_set_first_last_char(ctx, font_dict, (pdf_font *)font); |
281 | | /* ignore errors with widths... for now */ |
282 | 591 | (void)pdfi_font_create_widths(ctx, font_dict, (pdf_font*)font, 1.0); |
283 | | |
284 | | |
285 | 591 | code = pdfi_dict_get(ctx, font_dict, "Encoding", &obj); |
286 | 591 | if (code < 0) |
287 | 45 | goto font3_error; |
288 | | |
289 | 546 | code = pdfi_create_Encoding(ctx, obj, NULL, (pdf_obj **)&font->Encoding); |
290 | 546 | if (code < 0) |
291 | 15 | goto font3_error; |
292 | 531 | pdfi_countdown(obj); |
293 | | |
294 | 531 | font->PDF_font = font_dict; |
295 | 531 | pdfi_countup(font_dict); |
296 | | |
297 | 531 | if (ctx->args.ignoretounicode != true) { |
298 | 531 | code = pdfi_dict_get(ctx, font_dict, "ToUnicode", (pdf_obj **)&tounicode); |
299 | 531 | if (code >= 0 && pdfi_type_of(tounicode) == PDF_STREAM) { |
300 | 288 | pdf_cmap *tu = NULL; |
301 | 288 | code = pdfi_read_cmap(ctx, tounicode, &tu); |
302 | 288 | pdfi_countdown(tounicode); |
303 | 288 | tounicode = (pdf_obj *)tu; |
304 | 288 | } |
305 | 531 | if (code < 0 || (tounicode != NULL && pdfi_type_of(tounicode) != PDF_CMAP)) { |
306 | 244 | pdfi_countdown(tounicode); |
307 | 244 | tounicode = NULL; |
308 | 244 | code = 0; |
309 | 244 | } |
310 | 531 | } |
311 | 0 | else { |
312 | 0 | tounicode = NULL; |
313 | 0 | } |
314 | | |
315 | 531 | font->ToUnicode = tounicode; |
316 | 531 | tounicode = NULL; |
317 | | |
318 | 531 | code = replace_cache_entry(ctx, (pdf_obj *)font); |
319 | 531 | if (code < 0) |
320 | 0 | goto font3_error; |
321 | | |
322 | 531 | code = gs_definefont(ctx->font_dir, (gs_font *)font->pfont); |
323 | 531 | if (code < 0) |
324 | 0 | goto font3_error; |
325 | | |
326 | 531 | *ppdffont = (pdf_font *)font; |
327 | | |
328 | 531 | return code; |
329 | | |
330 | 91 | font3_error: |
331 | 91 | pdfi_countdown(obj); |
332 | 91 | pdfi_countdown(font); |
333 | 91 | return code; |
334 | 531 | } |