Coverage Report

Created: 2025-06-10 07:27

/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
}